From 4192458d3de91a322c4a3eba6c43ae6951e18802 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Tue, 16 Nov 2021 22:06:16 -0600 Subject: [PATCH] trying to get windows to work --- include/heartbreak.h | 24 +- lib/windows_x86_64/include/GLES3/gl3.h | 1192 +++ .../include/GLES3/gl3platform.h | 27 + lib/windows_x86_64/include/KHR/khrplatform.h | 290 + lib/windows_x86_64/include/small_windows.h | 373 + lib/windows_x86_64/include/stb_image.h | 7897 +++++++++++++++++ lib/windows_x86_64/include/stb_truetype.h | 5077 +++++++++++ lib/windows_x86_64/include/wasm.h | 723 ++ lib/windows_x86_64/include/wasmer.h | 896 ++ lib/windows_x86_64/lib/wasmer.dll | Bin 0 -> 8124416 bytes lib/windows_x86_64/lib/wasmer.lib | Bin 0 -> 51170400 bytes src/heartbreak.c | 8 +- src/heartbreak_input.c | 5 + src/heartbreak_system.c | 16 +- 14 files changed, 16512 insertions(+), 16 deletions(-) create mode 100644 lib/windows_x86_64/include/GLES3/gl3.h create mode 100644 lib/windows_x86_64/include/GLES3/gl3platform.h create mode 100644 lib/windows_x86_64/include/KHR/khrplatform.h create mode 100644 lib/windows_x86_64/include/small_windows.h create mode 100644 lib/windows_x86_64/include/stb_image.h create mode 100644 lib/windows_x86_64/include/stb_truetype.h create mode 100644 lib/windows_x86_64/include/wasm.h create mode 100644 lib/windows_x86_64/include/wasmer.h create mode 100644 lib/windows_x86_64/lib/wasmer.dll create mode 100644 lib/windows_x86_64/lib/wasmer.lib diff --git a/include/heartbreak.h b/include/heartbreak.h index 6ab0d32..f9accae 100644 --- a/include/heartbreak.h +++ b/include/heartbreak.h @@ -26,8 +26,18 @@ extern ImmediateRenderer renderer; // Helper macro to easily define WASM-interface functions // -#define _NUM_VALS(...) (sizeof((wasm_valkind_t[]) {__VA_ARGS__})/sizeof(wasm_valkind_t)) -#define _VALS(...) { _NUM_VALS(__VA_ARGS__), __VA_ARGS__ } +#ifdef _MSC_VER // Microsoft compilers +# define GET_ARG_COUNT(...) INTERNAL_EXPAND_ARGS_PRIVATE(INTERNAL_ARGS_AUGMENTER(__VA_ARGS__)) +# define INTERNAL_ARGS_AUGMENTER(...) unused, __VA_ARGS__ +# define INTERNAL_EXPAND(x) x +# define INTERNAL_EXPAND_ARGS_PRIVATE(...) INTERNAL_EXPAND(INTERNAL_GET_ARG_COUNT_PRIVATE(__VA_ARGS__, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +# define INTERNAL_GET_ARG_COUNT_PRIVATE(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, _33_, _34_, _35_, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, count, ...) count +#else // Non-Microsoft compilers +# define GET_ARG_COUNT(...) INTERNAL_GET_ARG_COUNT_PRIVATE(0, ## __VA_ARGS__, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +# define INTERNAL_GET_ARG_COUNT_PRIVATE(_0, _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, _33_, _34_, _35_, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, count, ...) count +#endif + +#define _VALS(...) ((WasmValkindBuffer) { GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__, 0 }) typedef struct { u32 count; @@ -38,8 +48,8 @@ typedef struct { char* name; wasm_func_callback_t func; - WasmValkindBuffer params; - WasmValkindBuffer results; + WasmValkindBuffer *params; + WasmValkindBuffer *results; } WasmFuncDefinition; #define STRINGIFY1(a) #a @@ -49,10 +59,14 @@ typedef struct { #define HEARTBREAK_FUNC_NAME(m, n) CONCAT3(__heartbreak_internal, m, n) #define HEARTBREAK_DEF_NAME(m, n) CONCAT3(__heartbreak_internal_def, m, n) #define HEARTBREAK_IMPORT_NAME(m, n) STRINGIFY1(m) "_" #n +#define HEARTBREAK_PARAM_NAME(m, n) CONCAT3(__heartbreak_internal_param_buffer, m, n) +#define HEARTBREAK_RESULT_NAME(m, n) CONCAT3(__heartbreak_internal_result_buffer, m, n) #define HEARTBREAK_DEF(name, params_types, result_types) \ wasm_trap_t* HEARTBREAK_FUNC_NAME(HEARTBREAK_MODULE_NAME, name)(const wasm_val_vec_t* params, wasm_val_vec_t* results); \ - static const WasmFuncDefinition HEARTBREAK_DEF_NAME(HEARTBREAK_MODULE_NAME, name) = { HEARTBREAK_IMPORT_NAME(HEARTBREAK_MODULE_NAME, name), HEARTBREAK_FUNC_NAME(HEARTBREAK_MODULE_NAME, name), _VALS params_types, _VALS result_types }; \ + static WasmValkindBuffer HEARTBREAK_PARAM_NAME(HEARTBREAK_MODULE_NAME, name) = _VALS params_types; \ + static WasmValkindBuffer HEARTBREAK_RESULT_NAME(HEARTBREAK_MODULE_NAME, name) = _VALS result_types; \ + static WasmFuncDefinition HEARTBREAK_DEF_NAME(HEARTBREAK_MODULE_NAME, name) = (WasmFuncDefinition) { HEARTBREAK_IMPORT_NAME(HEARTBREAK_MODULE_NAME, name), HEARTBREAK_FUNC_NAME(HEARTBREAK_MODULE_NAME, name), & HEARTBREAK_PARAM_NAME(HEARTBREAK_MODULE_NAME, name), & HEARTBREAK_RESULT_NAME(HEARTBREAK_MODULE_NAME, name) }; \ \ wasm_trap_t* HEARTBREAK_FUNC_NAME(HEARTBREAK_MODULE_NAME, name)(const wasm_val_vec_t* params, wasm_val_vec_t* results) diff --git a/lib/windows_x86_64/include/GLES3/gl3.h b/lib/windows_x86_64/include/GLES3/gl3.h new file mode 100644 index 0000000..c2cbb4f --- /dev/null +++ b/lib/windows_x86_64/include/GLES3/gl3.h @@ -0,0 +1,1192 @@ +#ifndef __gles2_gl3_h_ +#define __gles2_gl3_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright 2013-2020 The Khronos Group Inc. +** SPDX-License-Identifier: MIT +** +** 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 +** https://github.com/KhronosGroup/OpenGL-Registry +*/ + +#include + +#ifndef GL_APIENTRYP +#define GL_APIENTRYP GL_APIENTRY* +#endif + +#ifndef GL_GLES_PROTOTYPES +#define GL_GLES_PROTOTYPES 1 +#endif + +/* Generated on date 20210922 */ + +/* Generated C header for: + * API: gles2 + * Profile: common + * Versions considered: 2\.[0-9]|3\.0 + * Versions emitted: .* + * Default extensions included: None + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef GL_ES_VERSION_2_0 +#define GL_ES_VERSION_2_0 1 +#include +typedef khronos_int8_t GLbyte; +typedef khronos_float_t GLclampf; +typedef khronos_int32_t GLfixed; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef void GLvoid; +typedef struct __GLsync *GLsync; +typedef khronos_int64_t GLint64; +typedef khronos_uint64_t GLuint64; +typedef unsigned int GLenum; +typedef unsigned int GLuint; +typedef char GLchar; +typedef khronos_float_t GLfloat; +typedef khronos_ssize_t GLsizeiptr; +typedef khronos_intptr_t GLintptr; +typedef unsigned int GLbitfield; +typedef int GLint; +typedef unsigned char GLboolean; +typedef int GLsizei; +typedef khronos_uint8_t GLubyte; +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_FUNC_ADD 0x8006 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#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_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 +#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_STREAM_DRAW 0x88E0 +#define GL_STATIC_DRAW 0x88E4 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_CULL_FACE 0x0B44 +#define GL_BLEND 0x0BE2 +#define GL_DITHER 0x0BD0 +#define GL_STENCIL_TEST 0x0B90 +#define GL_DEPTH_TEST 0x0B71 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_LINE_WIDTH 0x0B21 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#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_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VIEWPORT 0x0BA2 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_FIXED 0x140C +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_SHADER_TYPE 0x8B4F +#define GL_DELETE_STATUS 0x8B80 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_INVERT 0x150A +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE 0x1702 +#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_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#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_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_MIRRORED_REPEAT 0x8370 +#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_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 +#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_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_COMPILE_STATUS 0x8B81 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#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_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGB565 0x8D62 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#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_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_COLOR_ATTACHMENT0 0x8CE0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_NONE 0 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +typedef void (GL_APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (GL_APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (GL_APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); +typedef void (GL_APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); +typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); +typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); +typedef void (GL_APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); +typedef void (GL_APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); +typedef void (GL_APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); +typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (GL_APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +typedef void (GL_APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); +typedef void (GL_APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); +typedef void (GL_APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); +typedef void (GL_APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GL_APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (GL_APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef GLuint (GL_APIENTRYP PFNGLCREATEPROGRAMPROC) (void); +typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); +typedef void (GL_APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); +typedef void (GL_APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); +typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (GL_APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); +typedef void (GL_APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); +typedef void (GL_APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); +typedef void (GL_APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); +typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); +typedef void (GL_APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (GL_APIENTRYP PFNGLDISABLEPROC) (GLenum cap); +typedef void (GL_APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (GL_APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); +typedef void (GL_APIENTRYP PFNGLENABLEPROC) (GLenum cap); +typedef void (GL_APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (GL_APIENTRYP PFNGLFINISHPROC) (void); +typedef void (GL_APIENTRYP PFNGLFLUSHPROC) (void); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GL_APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); +typedef void (GL_APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (GL_APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); +typedef void (GL_APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (GL_APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLint (GL_APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (GL_APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLenum (GL_APIENTRYP PFNGLGETERRORPROC) (void); +typedef void (GL_APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); +typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (GL_APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +typedef void (GL_APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); +typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); +typedef GLint (GL_APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); +typedef void (GL_APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); +typedef GLboolean (GL_APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); +typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); +typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); +typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); +typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); +typedef GLboolean (GL_APIENTRYP PFNGLISSHADERPROC) (GLuint shader); +typedef GLboolean (GL_APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); +typedef void (GL_APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); +typedef void (GL_APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); +typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); +typedef void (GL_APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +typedef void (GL_APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); +typedef void (GL_APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length); +typedef void (GL_APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +typedef void (GL_APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (GL_APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (GL_APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); +typedef void (GL_APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); +typedef void (GL_APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GL_APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (GL_APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (GL_APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); +typedef void (GL_APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); +typedef void (GL_APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (GL_APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); +typedef void (GL_APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GL_APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GL_APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GL_APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GL_APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +#if GL_GLES_PROTOTYPES +GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); +GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); +GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); +GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); +GL_APICALL void GL_APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GL_APICALL void GL_APIENTRY glBlendEquation (GLenum mode); +GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); +GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); +GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); +GL_APICALL void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GL_APICALL void GL_APIENTRY glClearDepthf (GLfloat d); +GL_APICALL void GL_APIENTRY glClearStencil (GLint s); +GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); +GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); +GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); +GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); +GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); +GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); +GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); +GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); +GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); +GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); +GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); +GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); +GL_APICALL void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f); +GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); +GL_APICALL void GL_APIENTRY glDisable (GLenum cap); +GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); +GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); +GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); +GL_APICALL void GL_APIENTRY glEnable (GLenum cap); +GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); +GL_APICALL void GL_APIENTRY glFinish (void); +GL_APICALL void GL_APIENTRY glFlush (void); +GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); +GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); +GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); +GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); +GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); +GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures); +GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); +GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *data); +GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); +GL_APICALL GLenum GL_APIENTRY glGetError (void); +GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *data); +GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *data); +GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GL_APICALL const GLubyte *GL_APIENTRY glGetString (GLenum name); +GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); +GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); +GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); +GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); +GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); +GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); +GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); +GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); +GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); +GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); +GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); +GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); +GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); +GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); +GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); +GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length); +GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); +GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); +GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); +GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); +GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat v0); +GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint v0); +GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); +GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); +GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); +GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); +GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); +GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); +GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); +GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); +GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); +GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); +GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); +GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_ES_VERSION_2_0 */ + +#ifndef GL_ES_VERSION_3_0 +#define GL_ES_VERSION_3_0 1 +typedef khronos_uint16_t GLhalf; +#define GL_READ_BUFFER 0x0C02 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_RED 0x1903 +#define GL_RGB8 0x8051 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#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_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#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_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#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_SRGB8_ALPHA8 0x8C43 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#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_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#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_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_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_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#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_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#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_2D_ARRAY 0x8DD7 +#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_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_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#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_TEXTURE_LAYER 0x8CD4 +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#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_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#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_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_RG8 0x822B +#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_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 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 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#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_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#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_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_INT_2_10_10_10_REV 0x8D9F +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#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_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_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_TEXTURE_IMMUTABLE_FORMAT 0x912F +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +typedef void (GL_APIENTRYP PFNGLREADBUFFERPROC) (GLenum src); +typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +typedef void (GL_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 (GL_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 (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (GL_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 (GL_APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); +typedef void (GL_APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (GL_APIENTRYP PFNGLISQUERYPROC) (GLuint id); +typedef void (GL_APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); +typedef void (GL_APIENTRYP PFNGLENDQUERYPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); +typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void *(GL_APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); +typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); +typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); +typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); +typedef void (GL_APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); +typedef void (GL_APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); +typedef void (GL_APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GL_APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (GL_APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (GL_APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); +typedef GLint (GL_APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (GL_APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); +typedef void (GL_APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (GL_APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GL_APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GL_APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (GL_APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (GL_APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); +typedef void (GL_APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +typedef GLuint (GL_APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); +typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +typedef void (GL_APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); +typedef GLboolean (GL_APIENTRYP PFNGLISSYNCPROC) (GLsync sync); +typedef void (GL_APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); +typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GL_APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GL_APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); +typedef void (GL_APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); +typedef void (GL_APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); +typedef void (GL_APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); +typedef void (GL_APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); +typedef GLboolean (GL_APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); +typedef void (GL_APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); +typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); +typedef void (GL_APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); +typedef void (GL_APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); +typedef void (GL_APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (GL_APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); +typedef void (GL_APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); +typedef void (GL_APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); +typedef void (GL_APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +typedef void (GL_APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); +#if GL_GLES_PROTOTYPES +GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src); +GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GL_APICALL void GL_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); +GL_APICALL void GL_APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GL_APICALL void GL_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); +GL_APICALL void GL_APIENTRY glGenQueries (GLsizei n, GLuint *ids); +GL_APICALL void GL_APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); +GL_APICALL GLboolean GL_APIENTRY glIsQuery (GLuint id); +GL_APICALL void GL_APIENTRY glBeginQuery (GLenum target, GLuint id); +GL_APICALL void GL_APIENTRY glEndQuery (GLenum target); +GL_APICALL void GL_APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); +GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenum target); +GL_APICALL void GL_APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); +GL_APICALL void GL_APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); +GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GL_APICALL void *GL_APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GL_APICALL void GL_APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); +GL_APICALL void GL_APIENTRY glBindVertexArray (GLuint array); +GL_APICALL void GL_APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); +GL_APICALL void GL_APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); +GL_APICALL GLboolean GL_APIENTRY glIsVertexArray (GLuint array); +GL_APICALL void GL_APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); +GL_APICALL void GL_APIENTRY glBeginTransformFeedback (GLenum primitiveMode); +GL_APICALL void GL_APIENTRY glEndTransformFeedback (void); +GL_APICALL void GL_APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GL_APICALL void GL_APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); +GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GL_APICALL void GL_APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GL_APICALL void GL_APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); +GL_APICALL void GL_APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); +GL_APICALL void GL_APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GL_APICALL void GL_APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); +GL_APICALL void GL_APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); +GL_APICALL void GL_APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); +GL_APICALL GLint GL_APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); +GL_APICALL void GL_APIENTRY glUniform1ui (GLint location, GLuint v0); +GL_APICALL void GL_APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); +GL_APICALL void GL_APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); +GL_APICALL void GL_APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GL_APICALL void GL_APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); +GL_APICALL void GL_APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); +GL_APICALL void GL_APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); +GL_APICALL void GL_APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); +GL_APICALL void GL_APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); +GL_APICALL void GL_APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); +GL_APICALL void GL_APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); +GL_APICALL void GL_APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GL_APICALL const GLubyte *GL_APIENTRY glGetStringi (GLenum name, GLuint index); +GL_APICALL void GL_APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GL_APICALL void GL_APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GL_APICALL void GL_APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); +GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GL_APICALL void GL_APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +GL_APICALL void GL_APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GL_APICALL void GL_APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GL_APICALL GLsync GL_APIENTRY glFenceSync (GLenum condition, GLbitfield flags); +GL_APICALL GLboolean GL_APIENTRY glIsSync (GLsync sync); +GL_APICALL void GL_APIENTRY glDeleteSync (GLsync sync); +GL_APICALL GLenum GL_APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GL_APICALL void GL_APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GL_APICALL void GL_APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); +GL_APICALL void GL_APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); +GL_APICALL void GL_APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); +GL_APICALL void GL_APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); +GL_APICALL void GL_APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); +GL_APICALL void GL_APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); +GL_APICALL GLboolean GL_APIENTRY glIsSampler (GLuint sampler); +GL_APICALL void GL_APIENTRY glBindSampler (GLuint unit, GLuint sampler); +GL_APICALL void GL_APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); +GL_APICALL void GL_APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); +GL_APICALL void GL_APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); +GL_APICALL void GL_APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); +GL_APICALL void GL_APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); +GL_APICALL void GL_APIENTRY glBindTransformFeedback (GLenum target, GLuint id); +GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); +GL_APICALL void GL_APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); +GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback (GLuint id); +GL_APICALL void GL_APIENTRY glPauseTransformFeedback (void); +GL_APICALL void GL_APIENTRY glResumeTransformFeedback (void); +GL_APICALL void GL_APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +GL_APICALL void GL_APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +GL_APICALL void GL_APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); +GL_APICALL void GL_APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); +GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GL_APICALL void GL_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); +#endif +#endif /* GL_ES_VERSION_3_0 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/windows_x86_64/include/GLES3/gl3platform.h b/lib/windows_x86_64/include/GLES3/gl3platform.h new file mode 100644 index 0000000..8699212 --- /dev/null +++ b/lib/windows_x86_64/include/GLES3/gl3platform.h @@ -0,0 +1,27 @@ +#ifndef __gl3platform_h_ +#define __gl3platform_h_ + +/* +** Copyright 2017-2020 The Khronos Group Inc. +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* Platform-specific types and definitions for OpenGL ES 3.X gl3.h + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * Please contribute modifications back to Khronos as pull requests on the + * public github repository: + * https://github.com/KhronosGroup/OpenGL-Registry + */ + +#include + +#ifndef GL_APICALL +#define GL_APICALL KHRONOS_APICALL +#endif + +#ifndef GL_APIENTRY +#define GL_APIENTRY KHRONOS_APIENTRY +#endif + +#endif /* __gl3platform_h_ */ diff --git a/lib/windows_x86_64/include/KHR/khrplatform.h b/lib/windows_x86_64/include/KHR/khrplatform.h new file mode 100644 index 0000000..dd22d92 --- /dev/null +++ b/lib/windows_x86_64/include/KHR/khrplatform.h @@ -0,0 +1,290 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 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. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/lib/windows_x86_64/include/small_windows.h b/lib/windows_x86_64/include/small_windows.h new file mode 100644 index 0000000..22d8f7a --- /dev/null +++ b/lib/windows_x86_64/include/small_windows.h @@ -0,0 +1,373 @@ +// Bill's Mini Windows.h from https://github.com/odin-lang/Odin/blob/master/src/gb/gb.h + +//////////////////////////////////////////////////////////////// +// +// Bill's Mini Windows.h +// +// + +#define GB_EXTERN extern +#define GB_DLL_EXPORT GB_EXTERN __declspec(dllexport) +#define GB_DLL_IMPORT GB_EXTERN __declspec(dllimport) + +#define WINAPI __stdcall +#define WINAPIV __cdecl +#define CALLBACK __stdcall +#define MAX_PATH 260 +#define CCHDEVICENAME 32 +#define CCHFORMNAME 32 + +typedef unsigned long DWORD; +typedef int WINBOOL; +#ifndef XFree86Server + #ifndef __OBJC__ + typedef WINBOOL BOOL; + #else + #define BOOL WINBOOL + #endif +typedef unsigned char BYTE; +#endif +typedef unsigned short WORD; +typedef float FLOAT; +typedef int INT; +typedef unsigned int UINT; +typedef short SHORT; +typedef long LONG; +typedef long long LONGLONG; +typedef unsigned short USHORT; +typedef unsigned long ULONG; +typedef unsigned long long ULONGLONG; + +typedef UINT WPARAM; +typedef LONG LPARAM; +typedef LONG LRESULT; +#ifndef _HRESULT_DEFINED +typedef LONG HRESULT; +#define _HRESULT_DEFINED +#endif +#ifndef XFree86Server +typedef WORD ATOM; +#endif /* XFree86Server */ +typedef void *HANDLE; +typedef HANDLE HGLOBAL; +typedef HANDLE HLOCAL; +typedef HANDLE GLOBALHANDLE; +typedef HANDLE LOCALHANDLE; +typedef void *HGDIOBJ; + +#define DECLARE_HANDLE(name) typedef HANDLE name +DECLARE_HANDLE(HACCEL); +DECLARE_HANDLE(HBITMAP); +DECLARE_HANDLE(HBRUSH); +DECLARE_HANDLE(HCOLORSPACE); +DECLARE_HANDLE(HDC); +DECLARE_HANDLE(HGLRC); +DECLARE_HANDLE(HDESK); +DECLARE_HANDLE(HENHMETAFILE); +DECLARE_HANDLE(HFONT); +DECLARE_HANDLE(HICON); +DECLARE_HANDLE(HKEY); +typedef HKEY *PHKEY; +DECLARE_HANDLE(HMENU); +DECLARE_HANDLE(HMETAFILE); +DECLARE_HANDLE(HINSTANCE); +typedef HINSTANCE HMODULE; +DECLARE_HANDLE(HPALETTE); +DECLARE_HANDLE(HPEN); +DECLARE_HANDLE(HRGN); +DECLARE_HANDLE(HRSRC); +DECLARE_HANDLE(HSTR); +DECLARE_HANDLE(HTASK); +DECLARE_HANDLE(HWND); +DECLARE_HANDLE(HWINSTA); +DECLARE_HANDLE(HKL); +DECLARE_HANDLE(HRAWINPUT); +DECLARE_HANDLE(HMONITOR); +#undef DECLARE_HANDLE + +typedef int HFILE; +typedef HICON HCURSOR; +typedef DWORD COLORREF; +typedef int (WINAPI *FARPROC)(); +typedef int (WINAPI *NEARPROC)(); +typedef int (WINAPI *PROC)(); +typedef LRESULT (CALLBACK *WNDPROC)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +#if defined(_WIN64) +typedef unsigned __int64 ULONG_PTR; +typedef signed __int64 LONG_PTR; +#else +typedef unsigned long ULONG_PTR; +typedef signed long LONG_PTR; +#endif +typedef ULONG_PTR DWORD_PTR; + +typedef struct tagRECT { + LONG left; + LONG top; + LONG right; + LONG bottom; +} RECT; +typedef struct tagRECTL { + LONG left; + LONG top; + LONG right; + LONG bottom; +} RECTL; +typedef struct tagPOINT { + LONG x; + LONG y; +} POINT; +typedef struct tagSIZE { + LONG cx; + LONG cy; +} SIZE; +typedef struct tagPOINTS { + SHORT x; + SHORT y; +} POINTS; +typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + HANDLE lpSecurityDescriptor; + BOOL bInheritHandle; +} SECURITY_ATTRIBUTES; +typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore, + RelationNumaNode, + RelationCache, + RelationProcessorPackage, + RelationGroup, + RelationAll = 0xffff +} LOGICAL_PROCESSOR_RELATIONSHIP; +typedef enum _PROCESSOR_CACHE_TYPE { + CacheUnified, + CacheInstruction, + CacheData, + CacheTrace +} PROCESSOR_CACHE_TYPE; +typedef struct _CACHE_DESCRIPTOR { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD Size; + PROCESSOR_CACHE_TYPE Type; +} CACHE_DESCRIPTOR; +typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ULONG_PTR ProcessorMask; + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + union { + struct { + BYTE Flags; + } ProcessorCore; + struct { + DWORD NodeNumber; + } NumaNode; + CACHE_DESCRIPTOR Cache; + ULONGLONG Reserved[2]; + }; +} SYSTEM_LOGICAL_PROCESSOR_INFORMATION; +typedef struct _MEMORY_BASIC_INFORMATION { + void *BaseAddress; + void *AllocationBase; + DWORD AllocationProtect; + size_t RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; +} MEMORY_BASIC_INFORMATION; +typedef struct _SYSTEM_INFO { + union { + DWORD dwOemId; + struct { + WORD wProcessorArchitecture; + WORD wReserved; + }; + }; + DWORD dwPageSize; + void * lpMinimumApplicationAddress; + void * lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; +} SYSTEM_INFO; +typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + }; + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; +} LARGE_INTEGER; +typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + DWORD HighPart; + }; + struct { + DWORD LowPart; + DWORD HighPart; + } u; + ULONGLONG QuadPart; +} ULARGE_INTEGER; + +typedef struct _OVERLAPPED { + ULONG_PTR Internal; + ULONG_PTR InternalHigh; + union { + struct { + DWORD Offset; + DWORD OffsetHigh; + }; + void *Pointer; + }; + HANDLE hEvent; +} OVERLAPPED; +typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME; +typedef struct _WIN32_FIND_DATAW { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + wchar_t cFileName[MAX_PATH]; + wchar_t cAlternateFileName[14]; +} WIN32_FIND_DATAW; +typedef struct _WIN32_FILE_ATTRIBUTE_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; +} WIN32_FILE_ATTRIBUTE_DATA; +typedef enum _GET_FILEEX_INFO_LEVELS { + GetFileExInfoStandard, + GetFileExMaxInfoLevel +} GET_FILEEX_INFO_LEVELS; + +#define INFINITE 0xffffffffl +#define INVALID_HANDLE_VALUE ((void *)(intptr_t)(-1)) + + +typedef DWORD WINAPI THREAD_START_ROUTINE(void *parameter); + +GB_DLL_IMPORT DWORD WINAPI GetLastError (void); +GB_DLL_IMPORT BOOL WINAPI CloseHandle (HANDLE object); +GB_DLL_IMPORT HANDLE WINAPI CreateSemaphoreA (SECURITY_ATTRIBUTES *semaphore_attributes, LONG initial_count, + LONG maximum_count, char const *name); +GB_DLL_IMPORT BOOL WINAPI ReleaseSemaphore (HANDLE semaphore, LONG release_count, LONG *previous_count); +GB_DLL_IMPORT DWORD WINAPI WaitForSingleObject(HANDLE handle, DWORD milliseconds); +GB_DLL_IMPORT HANDLE WINAPI CreateThread (SECURITY_ATTRIBUTES *semaphore_attributes, size_t stack_size, + THREAD_START_ROUTINE *start_address, void *parameter, + DWORD creation_flags, DWORD *thread_id); +GB_DLL_IMPORT DWORD WINAPI GetThreadId (HANDLE handle); +GB_DLL_IMPORT void WINAPI RaiseException (DWORD, DWORD, DWORD, ULONG_PTR const *); + + +GB_DLL_IMPORT BOOL WINAPI GetLogicalProcessorInformation(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer, DWORD *return_length); +GB_DLL_IMPORT DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE thread, DWORD_PTR check_mask); +GB_DLL_IMPORT HANDLE WINAPI GetCurrentThread(void); + +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 +#define PAGE_WRITECOMBINE 0x400 + +#define MEM_COMMIT 0x1000 +#define MEM_RESERVE 0x2000 +#define MEM_DECOMMIT 0x4000 +#define MEM_RELEASE 0x8000 +#define MEM_FREE 0x10000 +#define MEM_PRIVATE 0x20000 +#define MEM_MAPPED 0x40000 +#define MEM_RESET 0x80000 +#define MEM_TOP_DOWN 0x100000 +#define MEM_LARGE_PAGES 0x20000000 +#define MEM_4MB_PAGES 0x80000000 + + + + +GB_DLL_IMPORT void * WINAPI VirtualAlloc (void *addr, size_t size, DWORD allocation_type, DWORD protect); +GB_DLL_IMPORT size_t WINAPI VirtualQuery (void const *address, MEMORY_BASIC_INFORMATION *buffer, size_t length); +GB_DLL_IMPORT BOOL WINAPI VirtualFree (void *address, size_t size, DWORD free_type); +GB_DLL_IMPORT void WINAPI GetSystemInfo(SYSTEM_INFO *system_info); + + +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_ALL 0x10000000 +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define ERROR_FILE_NOT_FOUND 2l +#define ERROR_ACCESS_DENIED 5L +#define ERROR_NO_MORE_FILES 18l +#define ERROR_FILE_EXISTS 80l +#define ERROR_ALREADY_EXISTS 183l +#define STD_INPUT_HANDLE ((DWORD)-10) +#define STD_OUTPUT_HANDLE ((DWORD)-11) +#define STD_ERROR_HANDLE ((DWORD)-12) + +GB_DLL_IMPORT int MultiByteToWideChar(UINT code_page, DWORD flags, char const * multi_byte_str, int multi_byte_len, wchar_t const *wide_char_str, int wide_char_len); +GB_DLL_IMPORT int WideCharToMultiByte(UINT code_page, DWORD flags, wchar_t const *wide_char_str, int wide_char_len, char const * multi_byte_str, int multi_byte_len); +GB_DLL_IMPORT BOOL WINAPI SetFilePointerEx(HANDLE file, LARGE_INTEGER distance_to_move, + LARGE_INTEGER *new_file_pointer, DWORD move_method); +GB_DLL_IMPORT BOOL WINAPI ReadFile (HANDLE file, void *buffer, DWORD bytes_to_read, DWORD *bytes_read, OVERLAPPED *overlapped); +GB_DLL_IMPORT BOOL WINAPI WriteFile (HANDLE file, void const *buffer, DWORD bytes_to_write, DWORD *bytes_written, OVERLAPPED *overlapped); +GB_DLL_IMPORT HANDLE WINAPI CreateFileW (wchar_t const *path, DWORD desired_access, DWORD share_mode, + SECURITY_ATTRIBUTES *, DWORD creation_disposition, + DWORD flags_and_attributes, HANDLE template_file); +GB_DLL_IMPORT HANDLE WINAPI CreateFileA (char const *path, DWORD desired_access, DWORD share_mode, + SECURITY_ATTRIBUTES *, DWORD creation_disposition, + DWORD flags_and_attributes, HANDLE template_file); +GB_DLL_IMPORT HANDLE WINAPI GetStdHandle (DWORD std_handle); +GB_DLL_IMPORT BOOL WINAPI GetFileSizeEx (HANDLE file, LARGE_INTEGER *size); +GB_DLL_IMPORT BOOL WINAPI SetEndOfFile (HANDLE file); +GB_DLL_IMPORT HANDLE WINAPI FindFirstFileW (wchar_t const *path, WIN32_FIND_DATAW *data); +GB_DLL_IMPORT BOOL WINAPI FindClose (HANDLE find_file); +GB_DLL_IMPORT BOOL WINAPI GetFileAttributesExW(wchar_t const *path, GET_FILEEX_INFO_LEVELS info_level_id, WIN32_FILE_ATTRIBUTE_DATA *data); +GB_DLL_IMPORT BOOL WINAPI CopyFileW(wchar_t const *old_f, wchar_t const *new_f, BOOL fail_if_exists); +GB_DLL_IMPORT BOOL WINAPI MoveFileW(wchar_t const *old_f, wchar_t const *new_f); + +GB_DLL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart); + +GB_DLL_IMPORT HMODULE WINAPI LoadLibraryA (char const *filename); +GB_DLL_IMPORT BOOL WINAPI FreeLibrary (HMODULE module); +GB_DLL_IMPORT FARPROC WINAPI GetProcAddress(HMODULE module, char const *name); + +GB_DLL_IMPORT BOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *frequency); +GB_DLL_IMPORT BOOL WINAPI QueryPerformanceCounter (LARGE_INTEGER *counter); +GB_DLL_IMPORT void WINAPI GetSystemTimeAsFileTime (FILETIME *system_time_as_file_time); +GB_DLL_IMPORT void WINAPI Sleep(DWORD milliseconds); +GB_DLL_IMPORT void WINAPI ExitProcess(UINT exit_code); + +GB_DLL_IMPORT BOOL WINAPI SetEnvironmentVariableA(char const *name, char const *value); diff --git a/lib/windows_x86_64/include/stb_image.h b/lib/windows_x86_64/include/stb_image.h new file mode 100644 index 0000000..da7def8 --- /dev/null +++ b/lib/windows_x86_64/include/stb_image.h @@ -0,0 +1,7897 @@ +/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// 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 *channels_in_file -- outputs # of image components in image file +// int desired_channels -- 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, or NULL on an allocation failure or if the image is +// corrupt or invalid. 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 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// 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, *channels_in_file 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. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// 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). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. 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); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// 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). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +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; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#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. +STBIDEF 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" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +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) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context 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_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *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->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *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; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y), NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y), NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&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; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&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; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + 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 stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *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; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + 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; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *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; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// 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_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__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; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("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 STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__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 (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__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 (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("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, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("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]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__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_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - 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 +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// 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_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } 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 progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int 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_uc) (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 >= (1u << j)) return stbi__err("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_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + 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 const stbi__uint32 stbi__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 stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__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)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__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]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// 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 const stbi_uc stbi__jpeg_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 stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("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 ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("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 + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__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_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__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) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__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)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++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]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[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 + STBI__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] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__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_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__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 = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // 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 stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(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) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(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; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // 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) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + 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) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + 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); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // 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) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + 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) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__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; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + 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 stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("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; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // 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; + // these sizes can't be more than 17 bits + 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 + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + 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].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *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] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *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] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__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 stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *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] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *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; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + 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_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + 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_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *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; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + 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_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("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 = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *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_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } 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 { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *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; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__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 >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// 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 + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__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 stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *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, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + 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 stbi__err("bad codelengths","Corrupt PNG"); + 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]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (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_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__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]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_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 stbi__zlength_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 stbi__zdist_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 stbi__zdist_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 stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 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,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 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 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__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 stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// 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 + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__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; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + 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) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_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 stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_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 : 65535); + 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 stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("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; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_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_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("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 stbi__err("too large", "Image too large to decode"); + if (scan == STBI__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 stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_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 (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && 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 (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) 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; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__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__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__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;/* >>= 1;*/ } + return n; +} + +static int stbi__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; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + 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 + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.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 = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__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; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + 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 = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("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 stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(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 index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(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 * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_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 ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + 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 = stbi__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; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 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 (stbi__get16be(s) != 3) + return stbi__errpuc("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.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("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 preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } 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 (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// 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/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__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 *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("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=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__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 = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *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; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + 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__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // 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; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + 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_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__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 + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("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 stbi__errpuc("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 stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("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; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__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_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__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 *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__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; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // 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: + stbi__getn(s, rgbe, 4); + stbi__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 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__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_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__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 = stbi__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 + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__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; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 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 stbi__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_uc 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.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' 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 - stbi__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 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +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/lib/windows_x86_64/include/stb_truetype.h b/lib/windows_x86_64/include/stb_truetype.h new file mode 100644 index 0000000..bbf2284 --- /dev/null +++ b/lib/windows_x86_64/include/stb_truetype.h @@ -0,0 +1,5077 @@ +// stb_truetype.h - v1.26 - public domain +// authored from 2009-2021 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.26 (2021-08-28) fix broken rasterizer +// 1.25 (2021-07-11) many fixes +// 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.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(); +} +#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 unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); +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, last; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + last = ttUSHORT(data + endCount + 2*item); + if (unicode_codepoint < start || unicode_codepoint > last) + 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 && vertices) 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) + 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: return -1; // unsupported + } + + 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)); + 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); + } + break; + } + + default: + return -1; // Unsupported definition type, return an error. + } + + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; +} + +// 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, sti; + + 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= pairSetCount) return 0; + + needle=glyph2; + r=pairValueCount-1; + l=0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 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; + } + } + } else + return 0; + break; + } + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + 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_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } + + default: + return 0; // Unsupported position format + } + } + } + + 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 float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) +{ + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; +} + +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) +{ + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +} + +static float stbtt__sized_triangle_area(float height, float width) +{ + return height * width / 2; +} + +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) * e->direction; + STBTT_assert(x >= 0 && x < len); + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); + scanline_fill[x] += height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, y_final, 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; + } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = y_top + dy * (x1+1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | xxxxx..|............|............|............| + // | | /- xx*xxxx........|............|............| + // | | dy < | xxxxxx..|............|............| + // y_final | | \- | xx*xxx.........|............| + // sy1 | | | | xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; + + sign = e->direction; + + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing-sy0); + + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + y_final = y_bottom; + dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; this + // is exactly what the variable 'area' stores. it also gets a contribution + // from the line segment within it. the THIRD pixel will get the first + // pixel's rectangle contribution, the second pixel's rectangle contribution, + // and its own contribution. the 'own contribution' is the same in every pixel except + // the leftmost and rightmost, a trapezoid that slides down in each pixel. + // the second pixel's contribution to the third pixel will be the + // rectangle 1 wide times the height change in the second pixel, which is dy. + + step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes for each step in x + // so the area advances by 'step' every time + + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; // area of trapezoid is 1*step/2 + area += step; + } + STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final-0.01f); + + // area covered in the last pixel is the rectangle from all the pixels to the left, + // plus the trapezoid filled by the line segment in this pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); + + // the rest of the line is filled based on the total height of the line segment in this pixel + 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 + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box + 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; + + // 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[0] = x; + 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 + a*x^2 + b*x + c = 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; + + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + // 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) + 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] = {0.f,0.f,0.f}; + float px,py,t,it,dist2; + 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); + } + dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + 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.25 (2021-07-11) many fixes +// 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) 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. +------------------------------------------------------------------------------ +*/ diff --git a/lib/windows_x86_64/include/wasm.h b/lib/windows_x86_64/include/wasm.h new file mode 100644 index 0000000..4a7e2c0 --- /dev/null +++ b/lib/windows_x86_64/include/wasm.h @@ -0,0 +1,723 @@ +// WebAssembly C API + +#ifndef WASM_H +#define WASM_H + +#include +#include +#include +#include +#include + +#ifndef WASM_API_EXTERN +#ifdef _WIN32 +#define WASM_API_EXTERN __declspec(dllimport) +#else +#define WASM_API_EXTERN +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auxiliaries + +// Machine types + +inline void assertions() { + static_assert(sizeof(float) == sizeof(uint32_t), "incompatible float type"); + static_assert(sizeof(double) == sizeof(uint64_t), "incompatible double type"); + static_assert(sizeof(intptr_t) == sizeof(uint32_t) || + sizeof(intptr_t) == sizeof(uint64_t), + "incompatible pointer type"); +} + +typedef char byte_t; +typedef float float32_t; +typedef double float64_t; + + +// Ownership + +#define own + +// The qualifier `own` is used to indicate ownership of data in this API. +// It is intended to be interpreted similar to a `const` qualifier: +// +// - `own wasm_xxx_t*` owns the pointed-to data +// - `own wasm_xxx_t` distributes to all fields of a struct or union `xxx` +// - `own wasm_xxx_vec_t` owns the vector as well as its elements(!) +// - an `own` function parameter passes ownership from caller to callee +// - an `own` function result passes ownership from callee to caller +// - an exception are `own` pointer parameters named `out`, which are copy-back +// output parameters passing back ownership from callee to caller +// +// Own data is created by `wasm_xxx_new` functions and some others. +// It must be released with the corresponding `wasm_xxx_delete` function. +// +// Deleting a reference does not necessarily delete the underlying object, +// it merely indicates that this owner no longer uses it. +// +// For vectors, `const wasm_xxx_vec_t` is used informally to indicate that +// neither the vector nor its elements should be modified. +// TODO: introduce proper `wasm_xxx_const_vec_t`? + + +#define WASM_DECLARE_OWN(name) \ + typedef struct wasm_##name##_t wasm_##name##_t; \ + \ + WASM_API_EXTERN void wasm_##name##_delete(own wasm_##name##_t*); + + +// Vectors + +#define WASM_DECLARE_VEC(name, ptr_or_none) \ + typedef struct wasm_##name##_vec_t { \ + size_t size; \ + wasm_##name##_t ptr_or_none* data; \ + } wasm_##name##_vec_t; \ + \ + WASM_API_EXTERN void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \ + WASM_API_EXTERN void wasm_##name##_vec_new_uninitialized( \ + own wasm_##name##_vec_t* out, size_t); \ + WASM_API_EXTERN void wasm_##name##_vec_new( \ + own wasm_##name##_vec_t* out, \ + size_t, own wasm_##name##_t ptr_or_none const[]); \ + WASM_API_EXTERN void wasm_##name##_vec_copy( \ + own wasm_##name##_vec_t* out, const wasm_##name##_vec_t*); \ + WASM_API_EXTERN void wasm_##name##_vec_delete(own wasm_##name##_vec_t*); + + +// Byte vectors + +typedef byte_t wasm_byte_t; +WASM_DECLARE_VEC(byte, ) + +typedef wasm_byte_vec_t wasm_name_t; + +#define wasm_name wasm_byte_vec +#define wasm_name_new wasm_byte_vec_new +#define wasm_name_new_empty wasm_byte_vec_new_empty +#define wasm_name_new_new_uninitialized wasm_byte_vec_new_uninitialized +#define wasm_name_copy wasm_byte_vec_copy +#define wasm_name_delete wasm_byte_vec_delete + +static inline void wasm_name_new_from_string( + own wasm_name_t* out, own const char* s +) { + wasm_name_new(out, strlen(s), s); +} + +static inline void wasm_name_new_from_string_nt( + own wasm_name_t* out, own const char* s +) { + wasm_name_new(out, strlen(s) + 1, s); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Environment + +// Configuration + +WASM_DECLARE_OWN(config) + +WASM_API_EXTERN own wasm_config_t* wasm_config_new(); + +// Embedders may provide custom functions for manipulating configs. + + +// Engine + +WASM_DECLARE_OWN(engine) + +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(); +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*); + + +// Store + +WASM_DECLARE_OWN(store) + +WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Type Representations + +// Type attributes + +typedef uint8_t wasm_mutability_t; +enum wasm_mutability_enum { + WASM_CONST, + WASM_VAR, +}; + +typedef struct wasm_limits_t { + uint32_t min; + uint32_t max; +} wasm_limits_t; + +static const uint32_t wasm_limits_max_default = 0xffffffff; + + +// Generic + +#define WASM_DECLARE_TYPE(name) \ + WASM_DECLARE_OWN(name) \ + WASM_DECLARE_VEC(name, *) \ + \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t*); + + +// Value Types + +WASM_DECLARE_TYPE(valtype) + +typedef uint8_t wasm_valkind_t; +enum wasm_valkind_enum { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, + WASM_ANYREF = 128, + WASM_FUNCREF, +}; + +WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t); + +WASM_API_EXTERN wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t*); + +static inline bool wasm_valkind_is_num(wasm_valkind_t k) { + return k < WASM_ANYREF; +} +static inline bool wasm_valkind_is_ref(wasm_valkind_t k) { + return k >= WASM_ANYREF; +} + +static inline bool wasm_valtype_is_num(const wasm_valtype_t* t) { + return wasm_valkind_is_num(wasm_valtype_kind(t)); +} +static inline bool wasm_valtype_is_ref(const wasm_valtype_t* t) { + return wasm_valkind_is_ref(wasm_valtype_kind(t)); +} + + +// Function Types + +WASM_DECLARE_TYPE(functype) + +WASM_API_EXTERN own wasm_functype_t* wasm_functype_new( + own wasm_valtype_vec_t* params, own wasm_valtype_vec_t* results); + +WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t*); +WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t*); + + +// Global Types + +WASM_DECLARE_TYPE(globaltype) + +WASM_API_EXTERN own wasm_globaltype_t* wasm_globaltype_new( + own wasm_valtype_t*, wasm_mutability_t); + +WASM_API_EXTERN const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t*); +WASM_API_EXTERN wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t*); + + +// Table Types + +WASM_DECLARE_TYPE(tabletype) + +WASM_API_EXTERN own wasm_tabletype_t* wasm_tabletype_new( + own wasm_valtype_t*, const wasm_limits_t*); + +WASM_API_EXTERN const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t*); +WASM_API_EXTERN const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t*); + + +// Memory Types + +WASM_DECLARE_TYPE(memorytype) + +WASM_API_EXTERN own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t*); + +WASM_API_EXTERN const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t*); + + +// Extern Types + +WASM_DECLARE_TYPE(externtype) + +typedef uint8_t wasm_externkind_t; +enum wasm_externkind_enum { + WASM_EXTERN_FUNC, + WASM_EXTERN_GLOBAL, + WASM_EXTERN_TABLE, + WASM_EXTERN_MEMORY, +}; + +WASM_API_EXTERN wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t*); + +WASM_API_EXTERN wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t*); + +WASM_API_EXTERN wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t*); +WASM_API_EXTERN wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t*); +WASM_API_EXTERN wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t*); +WASM_API_EXTERN wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t*); + +WASM_API_EXTERN const wasm_externtype_t* wasm_functype_as_externtype_const(const wasm_functype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_globaltype_as_externtype_const(const wasm_globaltype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_tabletype_as_externtype_const(const wasm_tabletype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_memorytype_as_externtype_const(const wasm_memorytype_t*); + +WASM_API_EXTERN const wasm_functype_t* wasm_externtype_as_functype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_globaltype_t* wasm_externtype_as_globaltype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_tabletype_t* wasm_externtype_as_tabletype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_memorytype_t* wasm_externtype_as_memorytype_const(const wasm_externtype_t*); + + +// Import Types + +WASM_DECLARE_TYPE(importtype) + +WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new( + own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*); + +WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*); +WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*); + + +// Export Types + +WASM_DECLARE_TYPE(exporttype) + +WASM_API_EXTERN own wasm_exporttype_t* wasm_exporttype_new( + own wasm_name_t*, own wasm_externtype_t*); + +WASM_API_EXTERN const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Objects + +// Values + +struct wasm_ref_t; + +typedef struct wasm_val_t { + wasm_valkind_t kind; + union { + int32_t i32; + int64_t i64; + float32_t f32; + float64_t f64; + struct wasm_ref_t* ref; + } of; +} wasm_val_t; + +WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v); +WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*); + +WASM_DECLARE_VEC(val, ) + + +// References + +#define WASM_DECLARE_REF_BASE(name) \ + WASM_DECLARE_OWN(name) \ + \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \ + WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \ + \ + WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \ + WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \ + WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \ + wasm_##name##_t*, void*, void (*)(void*)); + +#define WASM_DECLARE_REF(name) \ + WASM_DECLARE_REF_BASE(name) \ + \ + WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \ + WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \ + WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \ + WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*); + +#define WASM_DECLARE_SHARABLE_REF(name) \ + WASM_DECLARE_REF(name) \ + WASM_DECLARE_OWN(shared_##name) \ + \ + WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*); + + +WASM_DECLARE_REF_BASE(ref) + + +// Frames + +WASM_DECLARE_OWN(frame) +WASM_DECLARE_VEC(frame, *) +WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*); + +WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*); +WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*); + + +// Traps + +typedef wasm_name_t wasm_message_t; // null terminated + +WASM_DECLARE_REF(trap) + +WASM_API_EXTERN own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*); + +WASM_API_EXTERN void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out); +WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*); +WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out); + + +// Foreign Objects + +WASM_DECLARE_REF(foreign) + +WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*); + + +// Modules + +WASM_DECLARE_SHARABLE_REF(module) + +WASM_API_EXTERN own wasm_module_t* wasm_module_new( + wasm_store_t*, const wasm_byte_vec_t* binary); + +WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); + +WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); +WASM_API_EXTERN void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out); + +WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); +WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); + + +// Function Instances + +WASM_DECLARE_REF(func) + +typedef own wasm_trap_t* (*wasm_func_callback_t)( + const wasm_val_vec_t* args, own wasm_val_vec_t* results); +typedef own wasm_trap_t* (*wasm_func_callback_with_env_t)( + void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results); + +WASM_API_EXTERN own wasm_func_t* wasm_func_new( + wasm_store_t*, const wasm_functype_t*, wasm_func_callback_t); +WASM_API_EXTERN own wasm_func_t* wasm_func_new_with_env( + wasm_store_t*, const wasm_functype_t* type, wasm_func_callback_with_env_t, + void* env, void (*finalizer)(void*)); + +WASM_API_EXTERN own wasm_functype_t* wasm_func_type(const wasm_func_t*); +WASM_API_EXTERN size_t wasm_func_param_arity(const wasm_func_t*); +WASM_API_EXTERN size_t wasm_func_result_arity(const wasm_func_t*); + +WASM_API_EXTERN own wasm_trap_t* wasm_func_call( + const wasm_func_t*, const wasm_val_vec_t* args, wasm_val_vec_t* results); + + +// Global Instances + +WASM_DECLARE_REF(global) + +WASM_API_EXTERN own wasm_global_t* wasm_global_new( + wasm_store_t*, const wasm_globaltype_t*, const wasm_val_t*); + +WASM_API_EXTERN own wasm_globaltype_t* wasm_global_type(const wasm_global_t*); + +WASM_API_EXTERN void wasm_global_get(const wasm_global_t*, own wasm_val_t* out); +WASM_API_EXTERN void wasm_global_set(wasm_global_t*, const wasm_val_t*); + + +// Table Instances + +WASM_DECLARE_REF(table) + +typedef uint32_t wasm_table_size_t; + +WASM_API_EXTERN own wasm_table_t* wasm_table_new( + wasm_store_t*, const wasm_tabletype_t*, wasm_ref_t* init); + +WASM_API_EXTERN own wasm_tabletype_t* wasm_table_type(const wasm_table_t*); + +WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index); +WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*); + +WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*); +WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init); + + +// Memory Instances + +WASM_DECLARE_REF(memory) + +typedef uint32_t wasm_memory_pages_t; + +static const size_t MEMORY_PAGE_SIZE = 0x10000; + +WASM_API_EXTERN own wasm_memory_t* wasm_memory_new(wasm_store_t*, const wasm_memorytype_t*); + +WASM_API_EXTERN own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t*); + +WASM_API_EXTERN byte_t* wasm_memory_data(wasm_memory_t*); +WASM_API_EXTERN size_t wasm_memory_data_size(const wasm_memory_t*); + +WASM_API_EXTERN wasm_memory_pages_t wasm_memory_size(const wasm_memory_t*); +WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); + + +// Externals + +WASM_DECLARE_REF(extern) +WASM_DECLARE_VEC(extern, *) + +WASM_API_EXTERN wasm_externkind_t wasm_extern_kind(const wasm_extern_t*); +WASM_API_EXTERN own wasm_externtype_t* wasm_extern_type(const wasm_extern_t*); + +WASM_API_EXTERN wasm_extern_t* wasm_func_as_extern(wasm_func_t*); +WASM_API_EXTERN wasm_extern_t* wasm_global_as_extern(wasm_global_t*); +WASM_API_EXTERN wasm_extern_t* wasm_table_as_extern(wasm_table_t*); +WASM_API_EXTERN wasm_extern_t* wasm_memory_as_extern(wasm_memory_t*); + +WASM_API_EXTERN wasm_func_t* wasm_extern_as_func(wasm_extern_t*); +WASM_API_EXTERN wasm_global_t* wasm_extern_as_global(wasm_extern_t*); +WASM_API_EXTERN wasm_table_t* wasm_extern_as_table(wasm_extern_t*); +WASM_API_EXTERN wasm_memory_t* wasm_extern_as_memory(wasm_extern_t*); + +WASM_API_EXTERN const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t*); + +WASM_API_EXTERN const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_global_t* wasm_extern_as_global_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_memory_t* wasm_extern_as_memory_const(const wasm_extern_t*); + + +// Module Instances + +WASM_DECLARE_REF(instance) + +WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( + wasm_store_t*, const wasm_module_t*, const wasm_extern_vec_t* imports, + own wasm_trap_t** +); + +WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out); + + +/////////////////////////////////////////////////////////////////////////////// +// Convenience + +// Vectors + +#define WASM_EMPTY_VEC {0, NULL} +#define WASM_ARRAY_VEC(array) {sizeof(array)/sizeof(*(array)), array} + + +// Value Type construction short-hands + +static inline own wasm_valtype_t* wasm_valtype_new_i32() { + return wasm_valtype_new(WASM_I32); +} +static inline own wasm_valtype_t* wasm_valtype_new_i64() { + return wasm_valtype_new(WASM_I64); +} +static inline own wasm_valtype_t* wasm_valtype_new_f32() { + return wasm_valtype_new(WASM_F32); +} +static inline own wasm_valtype_t* wasm_valtype_new_f64() { + return wasm_valtype_new(WASM_F64); +} + +static inline own wasm_valtype_t* wasm_valtype_new_anyref() { + return wasm_valtype_new(WASM_ANYREF); +} +static inline own wasm_valtype_t* wasm_valtype_new_funcref() { + return wasm_valtype_new(WASM_FUNCREF); +} + + +// Function Types construction short-hands + +static inline own wasm_functype_t* wasm_functype_new_0_0() { + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_0( + own wasm_valtype_t* p +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_1( + own wasm_valtype_t* r +) { + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_1( + own wasm_valtype_t* p, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_2( + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_2( + own wasm_valtype_t* p, own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + + +// Value construction short-hands + +static inline void wasm_val_init_ptr(own wasm_val_t* out, void* p) { +#if UINTPTR_MAX == UINT32_MAX + out->kind = WASM_I32; + out->of.i32 = (intptr_t)p; +#elif UINTPTR_MAX == UINT64_MAX + out->kind = WASM_I64; + out->of.i64 = (intptr_t)p; +#endif +} + +static inline void* wasm_val_ptr(const wasm_val_t* val) { +#if UINTPTR_MAX == UINT32_MAX + return (void*)(intptr_t)val->of.i32; +#elif UINTPTR_MAX == UINT64_MAX + return (void*)(intptr_t)val->of.i64; +#endif +} + +#define WASM_I32_VAL(i) (wasm_val_t) {.kind = WASM_I32, .of = {.i32 = i}} +#define WASM_I64_VAL(i) (wasm_val_t) {.kind = WASM_I64, .of = {.i64 = i}} +#define WASM_F32_VAL(z) (wasm_val_t) {.kind = WASM_F32, .of = {.f32 = z}} +#define WASM_F64_VAL(z) (wasm_val_t) {.kind = WASM_F64, .of = {.f64 = z}} +#define WASM_REF_VAL(r) (wasm_val_t) {.kind = WASM_ANYREF, .of = {.ref = r}} +#define WASM_INIT_VAL (wasm_val_t) {.kind = WASM_ANYREF, .of = {.ref = NULL}} + + +/////////////////////////////////////////////////////////////////////////////// + +#undef own + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // #ifdef WASM_H diff --git a/lib/windows_x86_64/include/wasmer.h b/lib/windows_x86_64/include/wasmer.h new file mode 100644 index 0000000..d700a4f --- /dev/null +++ b/lib/windows_x86_64/include/wasmer.h @@ -0,0 +1,896 @@ +// The Wasmer C/C++ header file compatible with the [`wasm-c-api`] +// standard API, as `wasm.h` (included here). +// +// This file is automatically generated by `lib/c-api/build.rs` of the +// [`wasmer-c-api`] Rust crate. +// +// # Stability +// +// The [`wasm-c-api`] standard API is a _living_ standard. There is no +// commitment for stability yet. We (Wasmer) will try our best to keep +// backward compatibility as much as possible. Nonetheless, some +// necessary API aren't yet standardized, and as such, we provide a +// custom API, e.g. `wasi_*` types and functions. +// +// The documentation makes it clear whether a function is unstable. +// +// When a type or a function will be deprecated, it will be marked as +// such with the appropriated compiler warning, and will be removed at +// the next release round. +// +// # Documentation +// +// At the time of writing, the [`wasm-c-api`] standard has no +// documentation. This file also does not include inline +// documentation. However, we have made (and we continue to make) an +// important effort to document everything. [See the documentation +// online][documentation]. Please refer to this page for the real +// canonical documentation. It also contains numerous examples. +// +// To generate the documentation locally, run `cargo doc --open` from +// within the [`wasmer-c-api`] Rust crate. +// +// [`wasm-c-api`]: https://github.com/WebAssembly/wasm-c-api +// [`wasmer-c-api`]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api +// [documentation]: https://wasmerio.github.io/wasmer/crates/wasmer_c_api/ + +#if !defined(WASMER_H_PRELUDE) + +#define WASMER_H_PRELUDE + +// Define the `ARCH_X86_X64` constant. +#if defined(MSVC) && defined(_M_AMD64) +# define ARCH_X86_64 +#elif (defined(GCC) || defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__) +# define ARCH_X86_64 +#endif + +// Compatibility with non-Clang compilers. +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif + +// Compatibility with non-Clang compilers. +#if !defined(__has_declspec_attribute) +# define __has_declspec_attribute(x) 0 +#endif + +// Define the `DEPRECATED` macro. +#if defined(GCC) || defined(__GNUC__) || __has_attribute(deprecated) +# define DEPRECATED(message) __attribute__((deprecated(message))) +#elif defined(MSVC) || __has_declspec_attribute(deprecated) +# define DEPRECATED(message) __declspec(deprecated(message)) +#endif + +// The `universal` feature has been enabled for this build. +#define WASMER_UNIVERSAL_ENABLED + +// The `compiler` feature has been enabled for this build. +#define WASMER_COMPILER_ENABLED + +// The `wasi` feature has been enabled for this build. +#define WASMER_WASI_ENABLED + +// The `middlewares` feature has been enabled for this build. +#define WASMER_MIDDLEWARES_ENABLED + +// This file corresponds to the following Wasmer version. +#define WASMER_VERSION "2.0.0" +#define WASMER_VERSION_MAJOR 2 +#define WASMER_VERSION_MINOR 0 +#define WASMER_VERSION_PATCH 0 +#define WASMER_VERSION_PRE "" + +#endif // WASMER_H_PRELUDE + + +// +// OK, here we go. The code below is automatically generated. +// + + +#ifndef WASMER_H +#define WASMER_H + +#include +#include +#include +#include +#include "wasm.h" + +#if defined(WASMER_WASI_ENABLED) +typedef enum wasi_version_t { +#if defined(WASMER_WASI_ENABLED) + INVALID_VERSION = -1, +#endif +#if defined(WASMER_WASI_ENABLED) + LATEST = 0, +#endif +#if defined(WASMER_WASI_ENABLED) + SNAPSHOT0 = 1, +#endif +#if defined(WASMER_WASI_ENABLED) + SNAPSHOT1 = 2, +#endif +} wasi_version_t; +#endif + +#if defined(WASMER_COMPILER_ENABLED) +typedef enum wasmer_compiler_t { + CRANELIFT = 0, + LLVM = 1, + SINGLEPASS = 2, +} wasmer_compiler_t; +#endif + +typedef enum wasmer_engine_t { + UNIVERSAL = 0, + DYLIB = 1, + STATICLIB = 2, +} wasmer_engine_t; + +typedef enum wasmer_parser_operator_t { + Unreachable, + Nop, + Block, + Loop, + If, + Else, + Try, + Catch, + CatchAll, + Delegate, + Throw, + Rethrow, + Unwind, + End, + Br, + BrIf, + BrTable, + Return, + Call, + CallIndirect, + ReturnCall, + ReturnCallIndirect, + Drop, + Select, + TypedSelect, + LocalGet, + LocalSet, + LocalTee, + GlobalGet, + GlobalSet, + I32Load, + I64Load, + F32Load, + F64Load, + I32Load8S, + I32Load8U, + I32Load16S, + I32Load16U, + I64Load8S, + I64Load8U, + I64Load16S, + I64Load16U, + I64Load32S, + I64Load32U, + I32Store, + I64Store, + F32Store, + F64Store, + I32Store8, + I32Store16, + I64Store8, + I64Store16, + I64Store32, + MemorySize, + MemoryGrow, + I32Const, + I64Const, + F32Const, + F64Const, + RefNull, + RefIsNull, + RefFunc, + I32Eqz, + I32Eq, + I32Ne, + I32LtS, + I32LtU, + I32GtS, + I32GtU, + I32LeS, + I32LeU, + I32GeS, + I32GeU, + I64Eqz, + I64Eq, + I64Ne, + I64LtS, + I64LtU, + I64GtS, + I64GtU, + I64LeS, + I64LeU, + I64GeS, + I64GeU, + F32Eq, + F32Ne, + F32Lt, + F32Gt, + F32Le, + F32Ge, + F64Eq, + F64Ne, + F64Lt, + F64Gt, + F64Le, + F64Ge, + I32Clz, + I32Ctz, + I32Popcnt, + I32Add, + I32Sub, + I32Mul, + I32DivS, + I32DivU, + I32RemS, + I32RemU, + I32And, + I32Or, + I32Xor, + I32Shl, + I32ShrS, + I32ShrU, + I32Rotl, + I32Rotr, + I64Clz, + I64Ctz, + I64Popcnt, + I64Add, + I64Sub, + I64Mul, + I64DivS, + I64DivU, + I64RemS, + I64RemU, + I64And, + I64Or, + I64Xor, + I64Shl, + I64ShrS, + I64ShrU, + I64Rotl, + I64Rotr, + F32Abs, + F32Neg, + F32Ceil, + F32Floor, + F32Trunc, + F32Nearest, + F32Sqrt, + F32Add, + F32Sub, + F32Mul, + F32Div, + F32Min, + F32Max, + F32Copysign, + F64Abs, + F64Neg, + F64Ceil, + F64Floor, + F64Trunc, + F64Nearest, + F64Sqrt, + F64Add, + F64Sub, + F64Mul, + F64Div, + F64Min, + F64Max, + F64Copysign, + I32WrapI64, + I32TruncF32S, + I32TruncF32U, + I32TruncF64S, + I32TruncF64U, + I64ExtendI32S, + I64ExtendI32U, + I64TruncF32S, + I64TruncF32U, + I64TruncF64S, + I64TruncF64U, + F32ConvertI32S, + F32ConvertI32U, + F32ConvertI64S, + F32ConvertI64U, + F32DemoteF64, + F64ConvertI32S, + F64ConvertI32U, + F64ConvertI64S, + F64ConvertI64U, + F64PromoteF32, + I32ReinterpretF32, + I64ReinterpretF64, + F32ReinterpretI32, + F64ReinterpretI64, + I32Extend8S, + I32Extend16S, + I64Extend8S, + I64Extend16S, + I64Extend32S, + I32TruncSatF32S, + I32TruncSatF32U, + I32TruncSatF64S, + I32TruncSatF64U, + I64TruncSatF32S, + I64TruncSatF32U, + I64TruncSatF64S, + I64TruncSatF64U, + MemoryInit, + DataDrop, + MemoryCopy, + MemoryFill, + TableInit, + ElemDrop, + TableCopy, + TableFill, + TableGet, + TableSet, + TableGrow, + TableSize, + MemoryAtomicNotify, + MemoryAtomicWait32, + MemoryAtomicWait64, + AtomicFence, + I32AtomicLoad, + I64AtomicLoad, + I32AtomicLoad8U, + I32AtomicLoad16U, + I64AtomicLoad8U, + I64AtomicLoad16U, + I64AtomicLoad32U, + I32AtomicStore, + I64AtomicStore, + I32AtomicStore8, + I32AtomicStore16, + I64AtomicStore8, + I64AtomicStore16, + I64AtomicStore32, + I32AtomicRmwAdd, + I64AtomicRmwAdd, + I32AtomicRmw8AddU, + I32AtomicRmw16AddU, + I64AtomicRmw8AddU, + I64AtomicRmw16AddU, + I64AtomicRmw32AddU, + I32AtomicRmwSub, + I64AtomicRmwSub, + I32AtomicRmw8SubU, + I32AtomicRmw16SubU, + I64AtomicRmw8SubU, + I64AtomicRmw16SubU, + I64AtomicRmw32SubU, + I32AtomicRmwAnd, + I64AtomicRmwAnd, + I32AtomicRmw8AndU, + I32AtomicRmw16AndU, + I64AtomicRmw8AndU, + I64AtomicRmw16AndU, + I64AtomicRmw32AndU, + I32AtomicRmwOr, + I64AtomicRmwOr, + I32AtomicRmw8OrU, + I32AtomicRmw16OrU, + I64AtomicRmw8OrU, + I64AtomicRmw16OrU, + I64AtomicRmw32OrU, + I32AtomicRmwXor, + I64AtomicRmwXor, + I32AtomicRmw8XorU, + I32AtomicRmw16XorU, + I64AtomicRmw8XorU, + I64AtomicRmw16XorU, + I64AtomicRmw32XorU, + I32AtomicRmwXchg, + I64AtomicRmwXchg, + I32AtomicRmw8XchgU, + I32AtomicRmw16XchgU, + I64AtomicRmw8XchgU, + I64AtomicRmw16XchgU, + I64AtomicRmw32XchgU, + I32AtomicRmwCmpxchg, + I64AtomicRmwCmpxchg, + I32AtomicRmw8CmpxchgU, + I32AtomicRmw16CmpxchgU, + I64AtomicRmw8CmpxchgU, + I64AtomicRmw16CmpxchgU, + I64AtomicRmw32CmpxchgU, + V128Load, + V128Store, + V128Const, + I8x16Splat, + I8x16ExtractLaneS, + I8x16ExtractLaneU, + I8x16ReplaceLane, + I16x8Splat, + I16x8ExtractLaneS, + I16x8ExtractLaneU, + I16x8ReplaceLane, + I32x4Splat, + I32x4ExtractLane, + I32x4ReplaceLane, + I64x2Splat, + I64x2ExtractLane, + I64x2ReplaceLane, + F32x4Splat, + F32x4ExtractLane, + F32x4ReplaceLane, + F64x2Splat, + F64x2ExtractLane, + F64x2ReplaceLane, + I8x16Eq, + I8x16Ne, + I8x16LtS, + I8x16LtU, + I8x16GtS, + I8x16GtU, + I8x16LeS, + I8x16LeU, + I8x16GeS, + I8x16GeU, + I16x8Eq, + I16x8Ne, + I16x8LtS, + I16x8LtU, + I16x8GtS, + I16x8GtU, + I16x8LeS, + I16x8LeU, + I16x8GeS, + I16x8GeU, + I32x4Eq, + I32x4Ne, + I32x4LtS, + I32x4LtU, + I32x4GtS, + I32x4GtU, + I32x4LeS, + I32x4LeU, + I32x4GeS, + I32x4GeU, + I64x2Eq, + I64x2Ne, + I64x2LtS, + I64x2GtS, + I64x2LeS, + I64x2GeS, + F32x4Eq, + F32x4Ne, + F32x4Lt, + F32x4Gt, + F32x4Le, + F32x4Ge, + F64x2Eq, + F64x2Ne, + F64x2Lt, + F64x2Gt, + F64x2Le, + F64x2Ge, + V128Not, + V128And, + V128AndNot, + V128Or, + V128Xor, + V128Bitselect, + V128AnyTrue, + I8x16Abs, + I8x16Neg, + I8x16AllTrue, + I8x16Bitmask, + I8x16Shl, + I8x16ShrS, + I8x16ShrU, + I8x16Add, + I8x16AddSatS, + I8x16AddSatU, + I8x16Sub, + I8x16SubSatS, + I8x16SubSatU, + I8x16MinS, + I8x16MinU, + I8x16MaxS, + I8x16MaxU, + I8x16Popcnt, + I16x8Abs, + I16x8Neg, + I16x8AllTrue, + I16x8Bitmask, + I16x8Shl, + I16x8ShrS, + I16x8ShrU, + I16x8Add, + I16x8AddSatS, + I16x8AddSatU, + I16x8Sub, + I16x8SubSatS, + I16x8SubSatU, + I16x8Mul, + I16x8MinS, + I16x8MinU, + I16x8MaxS, + I16x8MaxU, + I16x8ExtAddPairwiseI8x16S, + I16x8ExtAddPairwiseI8x16U, + I32x4Abs, + I32x4Neg, + I32x4AllTrue, + I32x4Bitmask, + I32x4Shl, + I32x4ShrS, + I32x4ShrU, + I32x4Add, + I32x4Sub, + I32x4Mul, + I32x4MinS, + I32x4MinU, + I32x4MaxS, + I32x4MaxU, + I32x4DotI16x8S, + I32x4ExtAddPairwiseI16x8S, + I32x4ExtAddPairwiseI16x8U, + I64x2Abs, + I64x2Neg, + I64x2AllTrue, + I64x2Bitmask, + I64x2Shl, + I64x2ShrS, + I64x2ShrU, + I64x2Add, + I64x2Sub, + I64x2Mul, + F32x4Ceil, + F32x4Floor, + F32x4Trunc, + F32x4Nearest, + F64x2Ceil, + F64x2Floor, + F64x2Trunc, + F64x2Nearest, + F32x4Abs, + F32x4Neg, + F32x4Sqrt, + F32x4Add, + F32x4Sub, + F32x4Mul, + F32x4Div, + F32x4Min, + F32x4Max, + F32x4PMin, + F32x4PMax, + F64x2Abs, + F64x2Neg, + F64x2Sqrt, + F64x2Add, + F64x2Sub, + F64x2Mul, + F64x2Div, + F64x2Min, + F64x2Max, + F64x2PMin, + F64x2PMax, + I32x4TruncSatF32x4S, + I32x4TruncSatF32x4U, + F32x4ConvertI32x4S, + F32x4ConvertI32x4U, + I8x16Swizzle, + I8x16Shuffle, + V128Load8Splat, + V128Load16Splat, + V128Load32Splat, + V128Load32Zero, + V128Load64Splat, + V128Load64Zero, + I8x16NarrowI16x8S, + I8x16NarrowI16x8U, + I16x8NarrowI32x4S, + I16x8NarrowI32x4U, + I16x8ExtendLowI8x16S, + I16x8ExtendHighI8x16S, + I16x8ExtendLowI8x16U, + I16x8ExtendHighI8x16U, + I32x4ExtendLowI16x8S, + I32x4ExtendHighI16x8S, + I32x4ExtendLowI16x8U, + I32x4ExtendHighI16x8U, + I64x2ExtendLowI32x4S, + I64x2ExtendHighI32x4S, + I64x2ExtendLowI32x4U, + I64x2ExtendHighI32x4U, + I16x8ExtMulLowI8x16S, + I16x8ExtMulHighI8x16S, + I16x8ExtMulLowI8x16U, + I16x8ExtMulHighI8x16U, + I32x4ExtMulLowI16x8S, + I32x4ExtMulHighI16x8S, + I32x4ExtMulLowI16x8U, + I32x4ExtMulHighI16x8U, + I64x2ExtMulLowI32x4S, + I64x2ExtMulHighI32x4S, + I64x2ExtMulLowI32x4U, + I64x2ExtMulHighI32x4U, + V128Load8x8S, + V128Load8x8U, + V128Load16x4S, + V128Load16x4U, + V128Load32x2S, + V128Load32x2U, + V128Load8Lane, + V128Load16Lane, + V128Load32Lane, + V128Load64Lane, + V128Store8Lane, + V128Store16Lane, + V128Store32Lane, + V128Store64Lane, + I8x16RoundingAverageU, + I16x8RoundingAverageU, + I16x8Q15MulrSatS, + F32x4DemoteF64x2Zero, + F64x2PromoteLowF32x4, + F64x2ConvertLowI32x4S, + F64x2ConvertLowI32x4U, + I32x4TruncSatF64x2SZero, + I32x4TruncSatF64x2UZero, +} wasmer_parser_operator_t; + +#if defined(WASMER_WASI_ENABLED) +typedef struct wasi_config_t wasi_config_t; +#endif + +#if defined(WASMER_WASI_ENABLED) +typedef struct wasi_env_t wasi_env_t; +#endif + +typedef struct wasmer_cpu_features_t wasmer_cpu_features_t; + +typedef struct wasmer_features_t wasmer_features_t; + +typedef struct wasmer_metering_t wasmer_metering_t; + +typedef struct wasmer_middleware_t wasmer_middleware_t; + +#if defined(WASMER_WASI_ENABLED) +typedef struct wasmer_named_extern_t wasmer_named_extern_t; +#endif + +typedef struct wasmer_target_t wasmer_target_t; + +typedef struct wasmer_triple_t wasmer_triple_t; + +#if defined(WASMER_WASI_ENABLED) +typedef struct wasmer_named_extern_vec_t { + uintptr_t size; + struct wasmer_named_extern_t **data; +} wasmer_named_extern_vec_t; +#endif + +typedef uint64_t (*wasmer_metering_cost_function_t)(enum wasmer_parser_operator_t wasm_operator); + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_arg(struct wasi_config_t *config, const char *arg); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_capture_stderr(struct wasi_config_t *config); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_capture_stdout(struct wasi_config_t *config); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_env(struct wasi_config_t *config, const char *key, const char *value); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_inherit_stderr(struct wasi_config_t *config); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_inherit_stdin(struct wasi_config_t *config); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_inherit_stdout(struct wasi_config_t *config); +#endif + +#if defined(WASMER_WASI_ENABLED) +bool wasi_config_mapdir(struct wasi_config_t *config, const char *alias, const char *dir); +#endif + +#if defined(WASMER_WASI_ENABLED) +struct wasi_config_t *wasi_config_new(const char *program_name); +#endif + +#if defined(WASMER_WASI_ENABLED) +bool wasi_config_preopen_dir(struct wasi_config_t *config, const char *dir); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasi_env_delete(struct wasi_env_t *_state); +#endif + +#if defined(WASMER_WASI_ENABLED) +struct wasi_env_t *wasi_env_new(struct wasi_config_t *config); +#endif + +#if defined(WASMER_WASI_ENABLED) +intptr_t wasi_env_read_stderr(struct wasi_env_t *env, char *buffer, uintptr_t buffer_len); +#endif + +#if defined(WASMER_WASI_ENABLED) +intptr_t wasi_env_read_stdout(struct wasi_env_t *env, char *buffer, uintptr_t buffer_len); +#endif + +#if defined(WASMER_WASI_ENABLED) +bool wasi_get_imports(const wasm_store_t *store, + const wasm_module_t *module, + const struct wasi_env_t *wasi_env, + wasm_extern_vec_t *imports); +#endif + +#if defined(WASMER_WASI_ENABLED) +wasm_func_t *wasi_get_start_function(wasm_instance_t *instance); +#endif + +#if defined(WASMER_WASI_ENABLED) +bool wasi_get_unordered_imports(const wasm_store_t *store, + const wasm_module_t *module, + const struct wasi_env_t *wasi_env, + struct wasmer_named_extern_vec_t *imports); +#endif + +#if defined(WASMER_WASI_ENABLED) +enum wasi_version_t wasi_get_wasi_version(const wasm_module_t *module); +#endif + +void wasm_config_canonicalize_nans(wasm_config_t *config, bool enable); + +void wasm_config_push_middleware(wasm_config_t *config, struct wasmer_middleware_t *middleware); + +#if defined(WASMER_COMPILER_ENABLED) +void wasm_config_set_compiler(wasm_config_t *config, enum wasmer_compiler_t compiler); +#endif + +void wasm_config_set_engine(wasm_config_t *config, enum wasmer_engine_t engine); + +void wasm_config_set_features(wasm_config_t *config, struct wasmer_features_t *features); + +void wasm_config_set_target(wasm_config_t *config, struct wasmer_target_t *target); + +bool wasmer_cpu_features_add(struct wasmer_cpu_features_t *cpu_features, + const wasm_name_t *feature); + +void wasmer_cpu_features_delete(struct wasmer_cpu_features_t *_cpu_features); + +struct wasmer_cpu_features_t *wasmer_cpu_features_new(void); + +bool wasmer_features_bulk_memory(struct wasmer_features_t *features, bool enable); + +void wasmer_features_delete(struct wasmer_features_t *_features); + +bool wasmer_features_memory64(struct wasmer_features_t *features, bool enable); + +bool wasmer_features_module_linking(struct wasmer_features_t *features, bool enable); + +bool wasmer_features_multi_memory(struct wasmer_features_t *features, bool enable); + +bool wasmer_features_multi_value(struct wasmer_features_t *features, bool enable); + +struct wasmer_features_t *wasmer_features_new(void); + +bool wasmer_features_reference_types(struct wasmer_features_t *features, bool enable); + +bool wasmer_features_simd(struct wasmer_features_t *features, bool enable); + +bool wasmer_features_tail_call(struct wasmer_features_t *features, bool enable); + +bool wasmer_features_threads(struct wasmer_features_t *features, bool enable); + +bool wasmer_is_compiler_available(enum wasmer_compiler_t compiler); + +bool wasmer_is_engine_available(enum wasmer_engine_t engine); + +bool wasmer_is_headless(void); + +int wasmer_last_error_length(void); + +int wasmer_last_error_message(char *buffer, int length); + +struct wasmer_middleware_t *wasmer_metering_as_middleware(struct wasmer_metering_t *metering); + +void wasmer_metering_delete(struct wasmer_metering_t *_metering); + +uint64_t wasmer_metering_get_remaining_points(const wasm_instance_t *instance); + +struct wasmer_metering_t *wasmer_metering_new(uint64_t initial_limit, + wasmer_metering_cost_function_t cost_function); + +bool wasmer_metering_points_are_exhausted(const wasm_instance_t *instance); + +void wasmer_metering_set_remaining_points(const wasm_instance_t *instance, uint64_t new_limit); + +void wasmer_module_name(const wasm_module_t *module, wasm_name_t *out); + +bool wasmer_module_set_name(wasm_module_t *module, const wasm_name_t *name); + +#if defined(WASMER_WASI_ENABLED) +const wasm_name_t *wasmer_named_extern_module(const struct wasmer_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +const wasm_name_t *wasmer_named_extern_name(const struct wasmer_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +const wasm_extern_t *wasmer_named_extern_unwrap(const struct wasmer_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasmer_named_extern_vec_copy(struct wasmer_named_extern_vec_t *out_ptr, + const struct wasmer_named_extern_vec_t *in_ptr); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasmer_named_extern_vec_delete(struct wasmer_named_extern_vec_t *ptr); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasmer_named_extern_vec_new(struct wasmer_named_extern_vec_t *out, + uintptr_t length, + struct wasmer_named_extern_t *const *init); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasmer_named_extern_vec_new_empty(struct wasmer_named_extern_vec_t *out); +#endif + +#if defined(WASMER_WASI_ENABLED) +void wasmer_named_extern_vec_new_uninitialized(struct wasmer_named_extern_vec_t *out, + uintptr_t length); +#endif + +void wasmer_target_delete(struct wasmer_target_t *_target); + +struct wasmer_target_t *wasmer_target_new(struct wasmer_triple_t *triple, + struct wasmer_cpu_features_t *cpu_features); + +void wasmer_triple_delete(struct wasmer_triple_t *_triple); + +struct wasmer_triple_t *wasmer_triple_new(const wasm_name_t *triple); + +struct wasmer_triple_t *wasmer_triple_new_from_host(void); + +const char *wasmer_version(void); + +uint8_t wasmer_version_major(void); + +uint8_t wasmer_version_minor(void); + +uint8_t wasmer_version_patch(void); + +const char *wasmer_version_pre(void); + +void wat2wasm(const wasm_byte_vec_t *wat, wasm_byte_vec_t *out); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* WASMER_H */ diff --git a/lib/windows_x86_64/lib/wasmer.dll b/lib/windows_x86_64/lib/wasmer.dll new file mode 100644 index 0000000000000000000000000000000000000000..45f9685d845cf55a57f114068cd0e7601ade4b6b GIT binary patch literal 8124416 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⪼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