Update external libraries

This commit is contained in:
Ray 2020-02-06 16:29:57 +01:00
parent ea40bda88c
commit 6c7685da3f
7 changed files with 886 additions and 503 deletions

406
src/external/cgltf.h vendored
View file

@ -1,7 +1,7 @@
/** /**
* cgltf - a single-file glTF 2.0 parser written in C99. * cgltf - a single-file glTF 2.0 parser written in C99.
* *
* Version: 1.4 * Version: 1.5
* *
* Website: https://github.com/jkuhlmann/cgltf * Website: https://github.com/jkuhlmann/cgltf
* *
@ -24,8 +24,8 @@
* *
* `cgltf_options` is the struct passed to `cgltf_parse()` to control * `cgltf_options` is the struct passed to `cgltf_parse()` to control
* parts of the parsing process. You can use it to force the file type * parts of the parsing process. You can use it to force the file type
* and provide memory allocation callbacks. Should be zero-initialized * and provide memory allocation as well as file operation callbacks.
* to trigger default behavior. * Should be zero-initialized to trigger default behavior.
* *
* `cgltf_data` is the struct allocated and filled by `cgltf_parse()`. * `cgltf_data` is the struct allocated and filled by `cgltf_parse()`.
* It generally mirrors the glTF format as described by the spec (see * It generally mirrors the glTF format as described by the spec (see
@ -72,6 +72,11 @@
* size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns
* false if the passed-in element_size is too small, or if the accessor is sparse. * false if the passed-in element_size is too small, or if the accessor is sparse.
* *
* `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading
* vector types and does not support matrix types. The passed-in element size is the number of uints
* in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in
* element_size is too small, or if the accessor is sparse.
*
* `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t
* and only works with single-component data types. * and only works with single-component data types.
* *
@ -96,6 +101,7 @@ extern "C" {
typedef size_t cgltf_size; typedef size_t cgltf_size;
typedef float cgltf_float; typedef float cgltf_float;
typedef int cgltf_int; typedef int cgltf_int;
typedef unsigned int cgltf_uint;
typedef int cgltf_bool; typedef int cgltf_bool;
typedef enum cgltf_file_type typedef enum cgltf_file_type
@ -105,15 +111,6 @@ typedef enum cgltf_file_type
cgltf_file_type_glb, cgltf_file_type_glb,
} cgltf_file_type; } cgltf_file_type;
typedef struct cgltf_options
{
cgltf_file_type type; /* invalid == auto detect */
cgltf_size json_token_count; /* 0 == auto */
void* (*memory_alloc)(void* user, cgltf_size size);
void (*memory_free) (void* user, void* ptr);
void* memory_user_data;
} cgltf_options;
typedef enum cgltf_result typedef enum cgltf_result
{ {
cgltf_result_success, cgltf_result_success,
@ -128,6 +125,28 @@ typedef enum cgltf_result
cgltf_result_legacy_gltf, cgltf_result_legacy_gltf,
} cgltf_result; } cgltf_result;
typedef struct cgltf_memory_options
{
void* (*alloc)(void* user, cgltf_size size);
void (*free) (void* user, void* ptr);
void* user_data;
} cgltf_memory_options;
typedef struct cgltf_file_options
{
cgltf_result(*read)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data);
void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data);
void* user_data;
} cgltf_file_options;
typedef struct cgltf_options
{
cgltf_file_type type; /* invalid == auto detect */
cgltf_size json_token_count; /* 0 == auto */
cgltf_memory_options memory;
cgltf_file_options file;
} cgltf_options;
typedef enum cgltf_buffer_view_type typedef enum cgltf_buffer_view_type
{ {
cgltf_buffer_view_type_invalid, cgltf_buffer_view_type_invalid,
@ -560,8 +579,8 @@ typedef struct cgltf_data
const void* bin; const void* bin;
cgltf_size bin_size; cgltf_size bin_size;
void (*memory_free) (void* user, void* ptr); cgltf_memory_options memory;
void* memory_user_data; cgltf_file_options file;
} cgltf_data; } cgltf_data;
cgltf_result cgltf_parse( cgltf_result cgltf_parse(
@ -591,6 +610,7 @@ void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix)
void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix);
cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size); cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size);
cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index); cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
cgltf_size cgltf_num_components(cgltf_type type); cgltf_size cgltf_num_components(cgltf_type type);
@ -713,7 +733,7 @@ static void* cgltf_calloc(cgltf_options* options, size_t element_size, cgltf_siz
{ {
return NULL; return NULL;
} }
void* result = options->memory_alloc(options->memory_user_data, element_size * count); void* result = options->memory.alloc(options->memory.user_data, element_size * count);
if (!result) if (!result)
{ {
return NULL; return NULL;
@ -722,6 +742,71 @@ static void* cgltf_calloc(cgltf_options* options, size_t element_size, cgltf_siz
return result; return result;
} }
static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data)
{
(void)file_options;
void* (*memory_alloc)(void*, cgltf_size) = memory_options->alloc ? memory_options->alloc : &cgltf_default_alloc;
void (*memory_free)(void*, void*) = memory_options->free ? memory_options->free : &cgltf_default_free;
FILE* file = fopen(path, "rb");
if (!file)
{
return cgltf_result_file_not_found;
}
cgltf_size file_size = size ? *size : 0;
if (file_size == 0)
{
fseek(file, 0, SEEK_END);
long length = ftell(file);
if (length < 0)
{
fclose(file);
return cgltf_result_io_error;
}
fseek(file, 0, SEEK_SET);
file_size = (cgltf_size)length;
}
char* file_data = (char*)memory_alloc(memory_options->user_data, file_size);
if (!file_data)
{
fclose(file);
return cgltf_result_out_of_memory;
}
cgltf_size read_size = fread(file_data, 1, file_size, file);
fclose(file);
if (read_size != file_size)
{
memory_free(memory_options->user_data, file_data);
return cgltf_result_io_error;
}
if (size)
{
*size = file_size;
}
if (data)
{
*data = file_data;
}
return cgltf_result_success;
}
static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data)
{
(void)file_options;
void (*memfree)(void*, void*) = memory_options->free ? memory_options->free : &cgltf_default_free;
memfree(memory_options->user_data, data);
}
static cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data); static cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data);
cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_size size, cgltf_data** out_data) cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_size size, cgltf_data** out_data)
@ -737,13 +822,13 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s
} }
cgltf_options fixed_options = *options; cgltf_options fixed_options = *options;
if (fixed_options.memory_alloc == NULL) if (fixed_options.memory.alloc == NULL)
{ {
fixed_options.memory_alloc = &cgltf_default_alloc; fixed_options.memory.alloc = &cgltf_default_alloc;
} }
if (fixed_options.memory_free == NULL) if (fixed_options.memory.free == NULL)
{ {
fixed_options.memory_free = &cgltf_default_free; fixed_options.memory.free = &cgltf_default_free;
} }
uint32_t tmp; uint32_t tmp;
@ -863,49 +948,23 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg
return cgltf_result_invalid_options; return cgltf_result_invalid_options;
} }
void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc; void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc ? options->memory.alloc : &cgltf_default_alloc;
void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free; void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free;
cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
FILE* file = fopen(path, "rb"); void* file_data = NULL;
if (!file) cgltf_size file_size = 0;
cgltf_result result = file_read(&options->memory, &options->file, path, &file_size, &file_data);
if (result != cgltf_result_success)
{ {
return cgltf_result_file_not_found; return result;
} }
fseek(file, 0, SEEK_END); result = cgltf_parse(options, file_data, file_size, out_data);
long length = ftell(file);
if (length < 0)
{
fclose(file);
return cgltf_result_io_error;
}
fseek(file, 0, SEEK_SET);
char* file_data = (char*)memory_alloc(options->memory_user_data, length);
if (!file_data)
{
fclose(file);
return cgltf_result_out_of_memory;
}
cgltf_size file_size = (cgltf_size)length;
cgltf_size read_size = fread(file_data, 1, file_size, file);
fclose(file);
if (read_size != file_size)
{
memory_free(options->memory_user_data, file_data);
return cgltf_result_io_error;
}
cgltf_result result = cgltf_parse(options, file_data, file_size, out_data);
if (result != cgltf_result_success) if (result != cgltf_result_success)
{ {
memory_free(options->memory_user_data, file_data); memory_free(options->memory.user_data, file_data);
return result; return result;
} }
@ -935,10 +994,11 @@ static void cgltf_combine_paths(char* path, const char* base, const char* uri)
static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data) static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data)
{ {
void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc; void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc ? options->memory.alloc : &cgltf_default_alloc;
void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free; void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free;
cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
char* path = (char*)memory_alloc(options->memory_user_data, strlen(uri) + strlen(gltf_path) + 1); char* path = (char*)memory_alloc(options->memory.user_data, strlen(uri) + strlen(gltf_path) + 1);
if (!path) if (!path)
{ {
return cgltf_result_out_of_memory; return cgltf_result_out_of_memory;
@ -946,30 +1006,11 @@ static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_s
cgltf_combine_paths(path, gltf_path, uri); cgltf_combine_paths(path, gltf_path, uri);
FILE* file = fopen(path, "rb"); void* file_data = NULL;
cgltf_result result = file_read(&options->memory, &options->file, path, &size, &file_data);
memory_free(options->memory_user_data, path); if (result != cgltf_result_success)
if (!file)
{ {
return cgltf_result_file_not_found; return result;
}
char* file_data = (char*)memory_alloc(options->memory_user_data, size);
if (!file_data)
{
fclose(file);
return cgltf_result_out_of_memory;
}
cgltf_size read_size = fread(file_data, 1, size, file);
fclose(file);
if (read_size != size)
{
memory_free(options->memory_user_data, file_data);
return cgltf_result_io_error;
} }
*out_data = file_data; *out_data = file_data;
@ -979,10 +1020,10 @@ static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_s
cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data) cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data)
{ {
void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc; void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc ? options->memory.alloc : &cgltf_default_alloc;
void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free; void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free;
unsigned char* data = (unsigned char*)memory_alloc(options->memory_user_data, size); unsigned char* data = (unsigned char*)memory_alloc(options->memory.user_data, size);
if (!data) if (!data)
{ {
return cgltf_result_out_of_memory; return cgltf_result_out_of_memory;
@ -1007,7 +1048,7 @@ cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size s
if (index < 0) if (index < 0)
{ {
memory_free(options->memory_user_data, data); memory_free(options->memory.user_data, data);
return cgltf_result_io_error; return cgltf_result_io_error;
} }
@ -1372,155 +1413,157 @@ void cgltf_free(cgltf_data* data)
return; return;
} }
data->memory_free(data->memory_user_data, data->asset.copyright); void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = data->file.release ? data->file.release : cgltf_default_file_release;
data->memory_free(data->memory_user_data, data->asset.generator);
data->memory_free(data->memory_user_data, data->asset.version);
data->memory_free(data->memory_user_data, data->asset.min_version);
data->memory_free(data->memory_user_data, data->accessors); data->memory.free(data->memory.user_data, data->asset.copyright);
data->memory_free(data->memory_user_data, data->buffer_views); data->memory.free(data->memory.user_data, data->asset.generator);
data->memory.free(data->memory.user_data, data->asset.version);
data->memory.free(data->memory.user_data, data->asset.min_version);
data->memory.free(data->memory.user_data, data->accessors);
data->memory.free(data->memory.user_data, data->buffer_views);
for (cgltf_size i = 0; i < data->buffers_count; ++i) for (cgltf_size i = 0; i < data->buffers_count; ++i)
{ {
if (data->buffers[i].data != data->bin) if (data->buffers[i].data != data->bin)
{ {
data->memory_free(data->memory_user_data, data->buffers[i].data); file_release(&data->memory, &data->file, data->buffers[i].data);
} }
data->memory_free(data->memory_user_data, data->buffers[i].uri); data->memory.free(data->memory.user_data, data->buffers[i].uri);
} }
data->memory_free(data->memory_user_data, data->buffers); data->memory.free(data->memory.user_data, data->buffers);
for (cgltf_size i = 0; i < data->meshes_count; ++i) for (cgltf_size i = 0; i < data->meshes_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->meshes[i].name); data->memory.free(data->memory.user_data, data->meshes[i].name);
for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j) for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
{ {
for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
{ {
data->memory_free(data->memory_user_data, data->meshes[i].primitives[j].attributes[k].name); data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].attributes[k].name);
} }
data->memory_free(data->memory_user_data, data->meshes[i].primitives[j].attributes); data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].attributes);
for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
{ {
for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
{ {
data->memory_free(data->memory_user_data, data->meshes[i].primitives[j].targets[k].attributes[m].name); data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes[m].name);
} }
data->memory_free(data->memory_user_data, data->meshes[i].primitives[j].targets[k].attributes); data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes);
} }
data->memory_free(data->memory_user_data, data->meshes[i].primitives[j].targets); data->memory.free(data->memory.user_data, data->meshes[i].primitives[j].targets);
} }
data->memory_free(data->memory_user_data, data->meshes[i].primitives); data->memory.free(data->memory.user_data, data->meshes[i].primitives);
data->memory_free(data->memory_user_data, data->meshes[i].weights); data->memory.free(data->memory.user_data, data->meshes[i].weights);
for (cgltf_size j = 0; j < data->meshes[i].target_names_count; ++j) for (cgltf_size j = 0; j < data->meshes[i].target_names_count; ++j)
{ {
data->memory_free(data->memory_user_data, data->meshes[i].target_names[j]); data->memory.free(data->memory.user_data, data->meshes[i].target_names[j]);
} }
data->memory_free(data->memory_user_data, data->meshes[i].target_names); data->memory.free(data->memory.user_data, data->meshes[i].target_names);
} }
data->memory_free(data->memory_user_data, data->meshes); data->memory.free(data->memory.user_data, data->meshes);
for (cgltf_size i = 0; i < data->materials_count; ++i) for (cgltf_size i = 0; i < data->materials_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->materials[i].name); data->memory.free(data->memory.user_data, data->materials[i].name);
} }
data->memory_free(data->memory_user_data, data->materials); data->memory.free(data->memory.user_data, data->materials);
for (cgltf_size i = 0; i < data->images_count; ++i) for (cgltf_size i = 0; i < data->images_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->images[i].name); data->memory.free(data->memory.user_data, data->images[i].name);
data->memory_free(data->memory_user_data, data->images[i].uri); data->memory.free(data->memory.user_data, data->images[i].uri);
data->memory_free(data->memory_user_data, data->images[i].mime_type); data->memory.free(data->memory.user_data, data->images[i].mime_type);
} }
data->memory_free(data->memory_user_data, data->images); data->memory.free(data->memory.user_data, data->images);
for (cgltf_size i = 0; i < data->textures_count; ++i) for (cgltf_size i = 0; i < data->textures_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->textures[i].name); data->memory.free(data->memory.user_data, data->textures[i].name);
} }
data->memory_free(data->memory_user_data, data->textures); data->memory.free(data->memory.user_data, data->textures);
data->memory_free(data->memory_user_data, data->samplers); data->memory.free(data->memory.user_data, data->samplers);
for (cgltf_size i = 0; i < data->skins_count; ++i) for (cgltf_size i = 0; i < data->skins_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->skins[i].name); data->memory.free(data->memory.user_data, data->skins[i].name);
data->memory_free(data->memory_user_data, data->skins[i].joints); data->memory.free(data->memory.user_data, data->skins[i].joints);
} }
data->memory_free(data->memory_user_data, data->skins); data->memory.free(data->memory.user_data, data->skins);
for (cgltf_size i = 0; i < data->cameras_count; ++i) for (cgltf_size i = 0; i < data->cameras_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->cameras[i].name); data->memory.free(data->memory.user_data, data->cameras[i].name);
} }
data->memory_free(data->memory_user_data, data->cameras); data->memory.free(data->memory.user_data, data->cameras);
for (cgltf_size i = 0; i < data->lights_count; ++i) for (cgltf_size i = 0; i < data->lights_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->lights[i].name); data->memory.free(data->memory.user_data, data->lights[i].name);
} }
data->memory_free(data->memory_user_data, data->lights); data->memory.free(data->memory.user_data, data->lights);
for (cgltf_size i = 0; i < data->nodes_count; ++i) for (cgltf_size i = 0; i < data->nodes_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->nodes[i].name); data->memory.free(data->memory.user_data, data->nodes[i].name);
data->memory_free(data->memory_user_data, data->nodes[i].children); data->memory.free(data->memory.user_data, data->nodes[i].children);
data->memory_free(data->memory_user_data, data->nodes[i].weights); data->memory.free(data->memory.user_data, data->nodes[i].weights);
} }
data->memory_free(data->memory_user_data, data->nodes); data->memory.free(data->memory.user_data, data->nodes);
for (cgltf_size i = 0; i < data->scenes_count; ++i) for (cgltf_size i = 0; i < data->scenes_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->scenes[i].name); data->memory.free(data->memory.user_data, data->scenes[i].name);
data->memory_free(data->memory_user_data, data->scenes[i].nodes); data->memory.free(data->memory.user_data, data->scenes[i].nodes);
} }
data->memory_free(data->memory_user_data, data->scenes); data->memory.free(data->memory.user_data, data->scenes);
for (cgltf_size i = 0; i < data->animations_count; ++i) for (cgltf_size i = 0; i < data->animations_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->animations[i].name); data->memory.free(data->memory.user_data, data->animations[i].name);
data->memory_free(data->memory_user_data, data->animations[i].samplers); data->memory.free(data->memory.user_data, data->animations[i].samplers);
data->memory_free(data->memory_user_data, data->animations[i].channels); data->memory.free(data->memory.user_data, data->animations[i].channels);
} }
data->memory_free(data->memory_user_data, data->animations); data->memory.free(data->memory.user_data, data->animations);
for (cgltf_size i = 0; i < data->extensions_used_count; ++i) for (cgltf_size i = 0; i < data->extensions_used_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->extensions_used[i]); data->memory.free(data->memory.user_data, data->extensions_used[i]);
} }
data->memory_free(data->memory_user_data, data->extensions_used); data->memory.free(data->memory.user_data, data->extensions_used);
for (cgltf_size i = 0; i < data->extensions_required_count; ++i) for (cgltf_size i = 0; i < data->extensions_required_count; ++i)
{ {
data->memory_free(data->memory_user_data, data->extensions_required[i]); data->memory.free(data->memory.user_data, data->extensions_required[i]);
} }
data->memory_free(data->memory_user_data, data->extensions_required); data->memory.free(data->memory.user_data, data->extensions_required);
data->memory_free(data->memory_user_data, data->file_data); file_release(&data->memory, &data->file, data->file_data);
data->memory_free(data->memory_user_data, data); data->memory.free(data->memory.user_data, data);
} }
void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix) void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix)
@ -1787,6 +1830,77 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl
return element_count * floats_per_element; return element_count * floats_per_element;
} }
static cgltf_uint cgltf_component_read_uint(const void* in, cgltf_component_type component_type)
{
switch (component_type)
{
case cgltf_component_type_r_8:
return *((const int8_t*) in);
case cgltf_component_type_r_8u:
return *((const uint8_t*) in);
case cgltf_component_type_r_16:
return *((const int16_t*) in);
case cgltf_component_type_r_16u:
return *((const uint16_t*) in);
case cgltf_component_type_r_32u:
return *((const uint32_t*) in);
default:
return 0;
}
return 0;
}
static cgltf_bool cgltf_element_read_uint(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_uint* out, cgltf_size element_size)
{
cgltf_size num_components = cgltf_num_components(type);
if (element_size < num_components)
{
return 0;
}
// Reading integer matrices is not a valid use case
if (type == cgltf_type_mat2 || type == cgltf_type_mat3 || type == cgltf_type_mat4)
{
return 0;
}
cgltf_size component_size = cgltf_component_size(component_type);
for (cgltf_size i = 0; i < num_components; ++i)
{
out[i] = cgltf_component_read_uint(element + component_size * i, component_type);
}
return 1;
}
cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size)
{
if (accessor->is_sparse)
{
return 0;
}
if (accessor->buffer_view == NULL)
{
memset(out, 0, element_size * sizeof( cgltf_uint ));
return 1;
}
if (accessor->buffer_view->buffer->data == NULL)
{
return 0;
}
cgltf_size offset = accessor->offset + accessor->buffer_view->offset;
const uint8_t* element = (const uint8_t*) accessor->buffer_view->buffer->data;
element += offset + accessor->stride * index;
return cgltf_element_read_uint(element, accessor->type, accessor->component_type, out, element_size);
}
cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index) cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index)
{ {
if (accessor->is_sparse) if (accessor->is_sparse)
@ -1916,7 +2030,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke
return CGLTF_ERROR_JSON; return CGLTF_ERROR_JSON;
} }
int size = tokens[i].end - tokens[i].start; int size = tokens[i].end - tokens[i].start;
char* result = (char*)options->memory_alloc(options->memory_user_data, size + 1); char* result = (char*)options->memory.alloc(options->memory.user_data, size + 1);
if (!result) if (!result)
{ {
return CGLTF_ERROR_NOMEM; return CGLTF_ERROR_NOMEM;
@ -4387,7 +4501,7 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk,
options->json_token_count = token_count; options->json_token_count = token_count;
} }
jsmntok_t* tokens = (jsmntok_t*)options->memory_alloc(options->memory_user_data, sizeof(jsmntok_t) * (options->json_token_count + 1)); jsmntok_t* tokens = (jsmntok_t*)options->memory.alloc(options->memory.user_data, sizeof(jsmntok_t) * (options->json_token_count + 1));
if (!tokens) if (!tokens)
{ {
@ -4400,7 +4514,7 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk,
if (token_count <= 0) if (token_count <= 0)
{ {
options->memory_free(options->memory_user_data, tokens); options->memory.free(options->memory.user_data, tokens);
return cgltf_result_invalid_json; return cgltf_result_invalid_json;
} }
@ -4408,21 +4522,21 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk,
// for invalid JSON inputs this makes sure we don't perform out of bound reads of token data // for invalid JSON inputs this makes sure we don't perform out of bound reads of token data
tokens[token_count].type = JSMN_UNDEFINED; tokens[token_count].type = JSMN_UNDEFINED;
cgltf_data* data = (cgltf_data*)options->memory_alloc(options->memory_user_data, sizeof(cgltf_data)); cgltf_data* data = (cgltf_data*)options->memory.alloc(options->memory.user_data, sizeof(cgltf_data));
if (!data) if (!data)
{ {
options->memory_free(options->memory_user_data, tokens); options->memory.free(options->memory.user_data, tokens);
return cgltf_result_out_of_memory; return cgltf_result_out_of_memory;
} }
memset(data, 0, sizeof(cgltf_data)); memset(data, 0, sizeof(cgltf_data));
data->memory_free = options->memory_free; data->memory = options->memory;
data->memory_user_data = options->memory_user_data; data->file = options->file;
int i = cgltf_parse_json_root(options, tokens, 0, json_chunk, data); int i = cgltf_parse_json_root(options, tokens, 0, json_chunk, data);
options->memory_free(options->memory_user_data, tokens); options->memory.free(options->memory.user_data, tokens);
if (i < 0) if (i < 0)
{ {

View file

@ -1,4 +1,4 @@
/* stb_image - v2.23 - public domain image loader - http://nothings.org/stb /* stb_image - v2.25 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@ -48,10 +48,12 @@ LICENSE
RECENT REVISION HISTORY: RECENT REVISION HISTORY:
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.23 (2019-08-11) fix clang static analysis warning
2.22 (2019-03-04) gif fixes, fix warnings 2.22 (2019-03-04) gif fixes, fix warnings
2.21 (2019-02-25) fix typo in comment 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.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning 2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings 2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
@ -105,7 +107,8 @@ RECENT REVISION HISTORY:
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus
Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo
Christian Floisand Kevin Schmidt JR Smith github:darealshinji Christian Floisand Kevin Schmidt JR Smith github:darealshinji
Blazej Dariusz Roszkowski github:Michaelangel007 Brad Weinberger Matvey Cherevko github:Michaelangel007
Blazej Dariusz Roszkowski Alexander Veselov
*/ */
#ifndef STBI_INCLUDE_STB_IMAGE_H #ifndef STBI_INCLUDE_STB_IMAGE_H
@ -434,7 +437,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f);
// get a VERY brief reason for failure // get a VERY brief reason for failure
// NOT THREADSAFE // on most compilers (and ALL modern mainstream compilers) this is threadsafe
STBIDEF const char *stbi_failure_reason (void); STBIDEF const char *stbi_failure_reason (void);
// free the loaded image -- this is just free() // free the loaded image -- this is just free()
@ -467,6 +470,11 @@ 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 // 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); 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_flip_vertically_on_load_thread(int flag_true_if_should_flip);
// ZLIB client - used by PNG, available for other purposes // 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(const char *buffer, int len, int initial_size, int *outlen);
@ -563,6 +571,17 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#define stbi_inline __forceinline #define stbi_inline __forceinline
#endif #endif
#ifndef STBI_NO_THREAD_LOCALS
#if defined(__cplusplus) && __cplusplus >= 201103L
#define STBI_THREAD_LOCAL thread_local
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define STBI_THREAD_LOCAL _Thread_local
#elif defined(__GNUC__)
#define STBI_THREAD_LOCAL __thread
#elif defined(_MSC_VER)
#define STBI_THREAD_LOCAL __declspec(thread)
#endif
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
typedef unsigned short stbi__uint16; typedef unsigned short stbi__uint16;
@ -873,19 +892,24 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int
static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
#endif #endif
// this is not threadsafe static
static const char *stbi__g_failure_reason; #ifdef STBI_THREAD_LOCAL
STBI_THREAD_LOCAL
#endif
const char *stbi__g_failure_reason;
STBIDEF const char *stbi_failure_reason(void) STBIDEF const char *stbi_failure_reason(void)
{ {
return stbi__g_failure_reason; return stbi__g_failure_reason;
} }
#ifndef STBI_NO_FAILURE_STRINGS
static int stbi__err(const char *str) static int stbi__err(const char *str)
{ {
stbi__g_failure_reason = str; stbi__g_failure_reason = str;
return 0; return 0;
} }
#endif
static void *stbi__malloc(size_t size) static void *stbi__malloc(size_t size)
{ {
@ -924,11 +948,13 @@ static int stbi__mul2sizes_valid(int a, int b)
return a <= INT_MAX/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 // 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) static int stbi__mad2sizes_valid(int a, int b, int add)
{ {
return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, 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 // 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) static int stbi__mad3sizes_valid(int a, int b, int c, int add)
@ -946,12 +972,14 @@ static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
} }
#endif #endif
#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
// mallocs with size overflow checking // mallocs with size overflow checking
static void *stbi__malloc_mad2(int a, int b, int add) static void *stbi__malloc_mad2(int a, int b, int add)
{ {
if (!stbi__mad2sizes_valid(a, b, add)) return NULL; if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
return stbi__malloc(a*b + add); return stbi__malloc(a*b + add);
} }
#endif
static void *stbi__malloc_mad3(int a, int b, int c, int add) static void *stbi__malloc_mad3(int a, int b, int c, int add)
{ {
@ -995,13 +1023,29 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
#endif #endif
static int stbi__vertically_flip_on_load = 0; static int stbi__vertically_flip_on_load_global = 0;
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
{ {
stbi__vertically_flip_on_load = 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) 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 memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
@ -1023,6 +1067,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
#endif #endif
#ifndef STBI_NO_PSD #ifndef STBI_NO_PSD
if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
#else
STBI_NOTUSED(bpc);
#endif #endif
#ifndef STBI_NO_PIC #ifndef STBI_NO_PIC
if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
@ -1111,8 +1157,8 @@ static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int byt
stbi_uc *bytes = (stbi_uc *)image; stbi_uc *bytes = (stbi_uc *)image;
for (slice = 0; slice < z; ++slice) { for (slice = 0; slice < z; ++slice) {
stbi__vertical_flip(bytes, w, h, bytes_per_pixel); stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
bytes += slice_size; bytes += slice_size;
} }
} }
#endif #endif
@ -1198,7 +1244,7 @@ static FILE *stbi__fopen(char const *filename, char const *mode)
wchar_t wFilename[1024]; wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
return 0; return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
return 0; return 0;
@ -1300,15 +1346,15 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
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) 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; unsigned char *result;
stbi__context s; stbi__context s;
stbi__start_mem(&s,buffer,len); stbi__start_mem(&s,buffer,len);
result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
if (stbi__vertically_flip_on_load) { if (stbi__vertically_flip_on_load) {
stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
} }
return result; return result;
} }
#endif #endif
@ -1477,6 +1523,9 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s)
return 0; 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) stbi_inline static int stbi__at_eof(stbi__context *s)
{ {
if (s->io.read) { if (s->io.read) {
@ -1488,7 +1537,11 @@ stbi_inline static int stbi__at_eof(stbi__context *s)
return s->img_buffer >= s->img_buffer_end; 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) static void stbi__skip(stbi__context *s, int n)
{ {
if (n < 0) { if (n < 0) {
@ -1505,7 +1558,11 @@ static void stbi__skip(stbi__context *s, int n)
} }
s->img_buffer += n; 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) static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
{ {
if (s->io.read) { if (s->io.read) {
@ -1529,18 +1586,27 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
} else } else
return 0; 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) static int stbi__get16be(stbi__context *s)
{ {
int z = stbi__get8(s); int z = stbi__get8(s);
return (z << 8) + 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) static stbi__uint32 stbi__get32be(stbi__context *s)
{ {
stbi__uint32 z = stbi__get16be(s); stbi__uint32 z = stbi__get16be(s);
return (z << 16) + stbi__get16be(s); return (z << 16) + stbi__get16be(s);
} }
#endif
#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
// nothing // nothing
@ -1562,7 +1628,9 @@ static stbi__uint32 stbi__get32le(stbi__context *s)
#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings #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 // generic converter from built-in img_n to req_comp
@ -1578,7 +1646,11 @@ static stbi_uc stbi__compute_y(int r, int g, int b)
{ {
return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); 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) static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{ {
int i,j; int i,j;
@ -1622,12 +1694,20 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
STBI_FREE(data); STBI_FREE(data);
return good; 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) static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
{ {
return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); 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) static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{ {
int i,j; int i,j;
@ -1671,6 +1751,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r
STBI_FREE(data); STBI_FREE(data);
return good; return good;
} }
#endif
#ifndef STBI_NO_LINEAR #ifndef STBI_NO_LINEAR
static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
@ -4942,6 +5023,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
++s->img_n; ++s->img_n;
} }
STBI_FREE(z->expanded); z->expanded = NULL; STBI_FREE(z->expanded); z->expanded = NULL;
// end of PNG chunk, read and skip CRC
stbi__get32be(s);
return 1; return 1;
} }
@ -5111,7 +5194,7 @@ static int stbi__shiftsigned(unsigned int v, int shift, int bits)
v <<= -shift; v <<= -shift;
else else
v >>= shift; v >>= shift;
STBI_ASSERT(v >= 0 && v < 256); STBI_ASSERT(v < 256);
v >>= (8-bits); v >>= (8-bits);
STBI_ASSERT(bits >= 0 && bits <= 8); STBI_ASSERT(bits >= 0 && bits <= 8);
return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
@ -5121,6 +5204,7 @@ typedef struct
{ {
int bpp, offset, hsz; int bpp, offset, hsz;
unsigned int mr,mg,mb,ma, all_a; unsigned int mr,mg,mb,ma, all_a;
int extra_read;
} stbi__bmp_data; } stbi__bmp_data;
static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
@ -5133,6 +5217,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
info->offset = stbi__get32le(s); info->offset = stbi__get32le(s);
info->hsz = hsz = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s);
info->mr = info->mg = info->mb = info->ma = 0; info->mr = info->mg = info->mb = info->ma = 0;
info->extra_read = 14;
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
if (hsz == 12) { if (hsz == 12) {
@ -5176,6 +5261,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
info->mr = stbi__get32le(s); info->mr = stbi__get32le(s);
info->mg = stbi__get32le(s); info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s); info->mb = stbi__get32le(s);
info->extra_read += 12;
// not documented, but generated by photoshop and handled by mspaint // not documented, but generated by photoshop and handled by mspaint
if (info->mr == info->mg && info->mg == info->mb) { if (info->mr == info->mg && info->mg == info->mb) {
// ?!?!? // ?!?!?
@ -5232,10 +5318,13 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
if (info.hsz == 12) { if (info.hsz == 12) {
if (info.bpp < 24) if (info.bpp < 24)
psize = (info.offset - 14 - 24) / 3; psize = (info.offset - info.extra_read - 24) / 3;
} else { } else {
if (info.bpp < 16) if (info.bpp < 16)
psize = (info.offset - 14 - info.hsz) >> 2; psize = (info.offset - info.extra_read - info.hsz) >> 2;
}
if (psize == 0) {
STBI_ASSERT(info.offset == (s->img_buffer - s->buffer_start));
} }
if (info.bpp == 24 && ma == 0xff000000) if (info.bpp == 24 && ma == 0xff000000)
@ -5263,7 +5352,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
if (info.hsz != 12) stbi__get8(s); if (info.hsz != 12) stbi__get8(s);
pal[i][3] = 255; pal[i][3] = 255;
} }
stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); 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; 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 == 4) width = (s->img_x + 1) >> 1;
else if (info.bpp == 8) width = s->img_x; else if (info.bpp == 8) width = s->img_x;
@ -5312,7 +5401,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0; int z = 0;
int easy=0; int easy=0;
stbi__skip(s, info.offset - 14 - info.hsz); stbi__skip(s, info.offset - info.extra_read - info.hsz);
if (info.bpp == 24) width = 3 * s->img_x; if (info.bpp == 24) width = 3 * s->img_x;
else if (info.bpp == 16) width = 2*s->img_x; else if (info.bpp == 16) width = 2*s->img_x;
else /* bpp = 32 and pad = 0 */ width=0; else /* bpp = 32 and pad = 0 */ width=0;
@ -6202,7 +6291,7 @@ typedef struct
int w,h; int w,h;
stbi_uc *out; // output buffer (always 4 components) stbi_uc *out; // output buffer (always 4 components)
stbi_uc *background; // The current "background" as far as a gif is concerned stbi_uc *background; // The current "background" as far as a gif is concerned
stbi_uc *history; stbi_uc *history;
int flags, bgindex, ratio, transparent, eflags; int flags, bgindex, ratio, transparent, eflags;
stbi_uc pal[256][4]; stbi_uc pal[256][4];
stbi_uc lpal[256][4]; stbi_uc lpal[256][4];
@ -6290,7 +6379,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
{ {
stbi_uc *p, *c; stbi_uc *p, *c;
int idx; int idx;
// recurse to decode the prefixes, since the linked-list is backwards, // recurse to decode the prefixes, since the linked-list is backwards,
// and working backwards through an interleaved image would be nasty // and working backwards through an interleaved image would be nasty
@ -6299,12 +6388,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
if (g->cur_y >= g->max_y) return; if (g->cur_y >= g->max_y) return;
idx = g->cur_x + g->cur_y; idx = g->cur_x + g->cur_y;
p = &g->out[idx]; p = &g->out[idx];
g->history[idx / 4] = 1; g->history[idx / 4] = 1;
c = &g->color_table[g->codes[code].suffix * 4]; c = &g->color_table[g->codes[code].suffix * 4];
if (c[3] > 128) { // don't render transparent pixels; if (c[3] > 128) { // don't render transparent pixels;
p[0] = c[2]; p[0] = c[2];
p[1] = c[1]; p[1] = c[1];
p[2] = c[0]; p[2] = c[0];
@ -6413,14 +6502,14 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
// two back is the image from two frames ago, used for a very specific disposal format // 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) 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 dispose;
int first_frame; int first_frame;
int pi; int pi;
int pcount; int pcount;
STBI_NOTUSED(req_comp); STBI_NOTUSED(req_comp);
// on first frame, any non-written pixels get the background colour (non-transparent) // on first frame, any non-written pixels get the background colour (non-transparent)
first_frame = 0; first_frame = 0;
if (g->out == 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__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)) if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))
@ -6432,17 +6521,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
if (!g->out || !g->background || !g->history) if (!g->out || !g->background || !g->history)
return stbi__errpuc("outofmem", "Out of memory"); return stbi__errpuc("outofmem", "Out of memory");
// image is treated as "transparent" at the start - ie, nothing overwrites the current background; // 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" // 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. // color refers to the color that was there the previous frame.
memset(g->out, 0x00, 4 * pcount); memset(g->out, 0x00, 4 * pcount);
memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)
memset(g->history, 0x00, pcount); // pixels that were affected previous frame memset(g->history, 0x00, pcount); // pixels that were affected previous frame
first_frame = 1; first_frame = 1;
} else { } else {
// second frame - how do we dispoase of the previous one? // second frame - how do we dispoase of the previous one?
dispose = (g->eflags & 0x1C) >> 2; dispose = (g->eflags & 0x1C) >> 2;
pcount = g->w * g->h; pcount = g->w * g->h;
if ((dispose == 3) && (two_back == 0)) { if ((dispose == 3) && (two_back == 0)) {
dispose = 2; // if I don't have an image to revert back to, default to the old background dispose = 2; // if I don't have an image to revert back to, default to the old background
@ -6451,32 +6540,32 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
if (dispose == 3) { // use previous graphic if (dispose == 3) { // use previous graphic
for (pi = 0; pi < pcount; ++pi) { for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) { if (g->history[pi]) {
memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
} }
} }
} else if (dispose == 2) { } else if (dispose == 2) {
// restore what was changed last frame to background before that frame; // restore what was changed last frame to background before that frame;
for (pi = 0; pi < pcount; ++pi) { for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) { if (g->history[pi]) {
memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
} }
} }
} else { } else {
// This is a non-disposal case eithe way, so just // This is a non-disposal case eithe way, so just
// leave the pixels as is, and they will become the new background // leave the pixels as is, and they will become the new background
// 1: do not dispose // 1: do not dispose
// 0: not specified. // 0: not specified.
} }
// background is what out is after the undoing of the previou frame; // background is what out is after the undoing of the previou frame;
memcpy( g->background, g->out, 4 * g->w * g->h ); memcpy( g->background, g->out, 4 * g->w * g->h );
} }
// clear my history; // clear my history;
memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
for (;;) { for (;;) {
int tag = stbi__get8(s); int tag = stbi__get8(s);
switch (tag) { switch (tag) {
case 0x2C: /* Image Descriptor */ case 0x2C: /* Image Descriptor */
{ {
@ -6521,19 +6610,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
} else if (g->flags & 0x80) { } else if (g->flags & 0x80) {
g->color_table = (stbi_uc *) g->pal; g->color_table = (stbi_uc *) g->pal;
} else } else
return stbi__errpuc("missing color table", "Corrupt GIF"); return stbi__errpuc("missing color table", "Corrupt GIF");
o = stbi__process_gif_raster(s, g); o = stbi__process_gif_raster(s, g);
if (!o) return NULL; if (!o) return NULL;
// if this was the first frame, // if this was the first frame,
pcount = g->w * g->h; pcount = g->w * g->h;
if (first_frame && (g->bgindex > 0)) { if (first_frame && (g->bgindex > 0)) {
// if first frame, any pixel not drawn to gets the background color // if first frame, any pixel not drawn to gets the background color
for (pi = 0; pi < pcount; ++pi) { for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi] == 0) { 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; 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 ); memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
} }
} }
} }
@ -6544,7 +6633,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
case 0x21: // Comment Extension. case 0x21: // Comment Extension.
{ {
int len; int len;
int ext = stbi__get8(s); int ext = stbi__get8(s);
if (ext == 0xF9) { // Graphic Control Extension. if (ext == 0xF9) { // Graphic Control Extension.
len = stbi__get8(s); len = stbi__get8(s);
if (len == 4) { if (len == 4) {
@ -6553,23 +6642,23 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
// unset old transparent // unset old transparent
if (g->transparent >= 0) { if (g->transparent >= 0) {
g->pal[g->transparent][3] = 255; g->pal[g->transparent][3] = 255;
} }
if (g->eflags & 0x01) { if (g->eflags & 0x01) {
g->transparent = stbi__get8(s); g->transparent = stbi__get8(s);
if (g->transparent >= 0) { if (g->transparent >= 0) {
g->pal[g->transparent][3] = 0; g->pal[g->transparent][3] = 0;
} }
} else { } else {
// don't need transparent // don't need transparent
stbi__skip(s, 1); stbi__skip(s, 1);
g->transparent = -1; g->transparent = -1;
} }
} else { } else {
stbi__skip(s, len); stbi__skip(s, len);
break; break;
} }
} }
while ((len = stbi__get8(s)) != 0) { while ((len = stbi__get8(s)) != 0) {
stbi__skip(s, len); stbi__skip(s, len);
} }
@ -6588,15 +6677,15 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) 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)) { if (stbi__gif_test(s)) {
int layers = 0; int layers = 0;
stbi_uc *u = 0; stbi_uc *u = 0;
stbi_uc *out = 0; stbi_uc *out = 0;
stbi_uc *two_back = 0; stbi_uc *two_back = 0;
stbi__gif g; stbi__gif g;
int stride; int stride;
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
if (delays) { if (delays) {
*delays = 0; *delays = 0;
} }
do { do {
@ -6606,44 +6695,52 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
if (u) { if (u) {
*x = g.w; *x = g.w;
*y = g.h; *y = g.h;
++layers; ++layers;
stride = g.w * g.h * 4; stride = g.w * g.h * 4;
if (out) { if (out) {
out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride );
if (NULL == tmp) {
STBI_FREE(g.out);
STBI_FREE(g.history);
STBI_FREE(g.background);
return stbi__errpuc("outofmem", "Out of memory");
}
else
out = (stbi_uc*) tmp;
if (delays) { if (delays) {
*delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers );
} }
} else { } else {
out = (stbi_uc*)stbi__malloc( layers * stride ); out = (stbi_uc*)stbi__malloc( layers * stride );
if (delays) { if (delays) {
*delays = (int*) stbi__malloc( layers * sizeof(int) ); *delays = (int*) stbi__malloc( layers * sizeof(int) );
} }
} }
memcpy( out + ((layers - 1) * stride), u, stride ); memcpy( out + ((layers - 1) * stride), u, stride );
if (layers >= 2) { if (layers >= 2) {
two_back = out - 2 * stride; two_back = out - 2 * stride;
} }
if (delays) { if (delays) {
(*delays)[layers - 1U] = g.delay; (*delays)[layers - 1U] = g.delay;
} }
} }
} while (u != 0); } while (u != 0);
// free temp buffer; // free temp buffer;
STBI_FREE(g.out); STBI_FREE(g.out);
STBI_FREE(g.history); STBI_FREE(g.history);
STBI_FREE(g.background); STBI_FREE(g.background);
// do the final conversion after loading everything; // do the final conversion after loading everything;
if (req_comp && req_comp != 4) if (req_comp && req_comp != 4)
out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
*z = layers; *z = layers;
return out; return out;
} else { } else {
return stbi__errpuc("not GIF", "Image was not as a gif type."); return stbi__errpuc("not GIF", "Image was not as a gif type.");
} }
} }
@ -6661,7 +6758,7 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req
*y = g.h; *y = g.h;
// moved conversion to after successful load so that the same // moved conversion to after successful load so that the same
// can be done for multiple frames. // can be done for multiple frames.
if (req_comp && req_comp != 4) if (req_comp && req_comp != 4)
u = stbi__convert_format(u, 4, req_comp, g.w, g.h); u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
} else if (g.out) { } else if (g.out) {
@ -6669,9 +6766,9 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req
STBI_FREE(g.out); STBI_FREE(g.out);
} }
// free buffers needed for multiple frame loading; // free buffers needed for multiple frame loading;
STBI_FREE(g.history); STBI_FREE(g.history);
STBI_FREE(g.background); STBI_FREE(g.background);
return u; return u;
} }
@ -7334,7 +7431,7 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user
/* /*
revision history: revision history:
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning 2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings 2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug

View file

@ -20,8 +20,8 @@
output_pixels, out_w, out_h, 0, output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0) num_channels , alpha_chan , 0)
stbir_resize_uint8_srgb_edgemode( stbir_resize_uint8_srgb_edgemode(
input_pixels , in_w , in_h , 0, input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0, output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
// WRAP/REFLECT/ZERO // WRAP/REFLECT/ZERO
@ -159,6 +159,7 @@
Nathan Reed: warning fixes Nathan Reed: warning fixes
REVISIONS REVISIONS
0.97 (2020-02-02) fixed warning
0.96 (2019-03-04) fixed warnings 0.96 (2019-03-04) fixed warnings
0.95 (2017-07-23) fixed warnings 0.95 (2017-07-23) fixed warnings
0.94 (2017-03-18) fixed warnings 0.94 (2017-03-18) fixed warnings
@ -233,7 +234,7 @@ STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , i
int num_channels); int num_channels);
// The following functions interpret image data as gamma-corrected sRGB. // The following functions interpret image data as gamma-corrected sRGB.
// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, // Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
// or otherwise provide the index of the alpha channel. Flags value // or otherwise provide the index of the alpha channel. Flags value
// of 0 will probably do the right thing if you're not sure what // of 0 will probably do the right thing if you're not sure what
@ -306,19 +307,19 @@ typedef enum
STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context); void *alloc_context);
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context); void *alloc_context);
STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context); void *alloc_context);
@ -350,7 +351,7 @@ STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype, stbir_datatype datatype,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context); stbir_colorspace space, void *alloc_context);
@ -358,7 +359,7 @@ STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype, stbir_datatype datatype,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context, stbir_colorspace space, void *alloc_context,
float x_scale, float y_scale, float x_scale, float y_scale,
@ -368,7 +369,7 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype, stbir_datatype datatype,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context, stbir_colorspace space, void *alloc_context,
float s0, float t0, float s1, float t1); float s0, float t0, float s1, float t1);
@ -670,14 +671,14 @@ static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
}; };
static stbir_uint8 stbir__linear_to_srgb_uchar(float in) static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
{ {
static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
static const stbir__FP32 minval = { (127-13) << 23 }; static const stbir__FP32 minval = { (127-13) << 23 };
stbir_uint32 tab,bias,scale,t; stbir_uint32 tab,bias,scale,t;
stbir__FP32 f; stbir__FP32 f;
// Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
// The tests are carefully written so that NaNs map to 0, same as in the reference // The tests are carefully written so that NaNs map to 0, same as in the reference
// implementation. // implementation.
@ -685,13 +686,13 @@ static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
in = minval.f; in = minval.f;
if (in > almostone.f) if (in > almostone.f)
in = almostone.f; in = almostone.f;
// Do the table lookup and unpack bias, scale // Do the table lookup and unpack bias, scale
f.f = in; f.f = in;
tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
bias = (tab >> 16) << 9; bias = (tab >> 16) << 9;
scale = tab & 0xffff; scale = tab & 0xffff;
// Grab next-highest mantissa bits and perform linear interpolation // Grab next-highest mantissa bits and perform linear interpolation
t = (f.u >> 12) & 0xff; t = (f.u >> 12) & 0xff;
return (unsigned char) ((bias + scale*t) >> 16); return (unsigned char) ((bias + scale*t) >> 16);
@ -1238,7 +1239,7 @@ static float* stbir__get_decode_buffer(stbir__info* stbir_info)
return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
} }
#define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace)) #define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
static void stbir__decode_scanline(stbir__info* stbir_info, int n) static void stbir__decode_scanline(stbir__info* stbir_info, int n)
{ {
@ -2445,7 +2446,7 @@ static int stbir__resize_arbitrary(
return 0; return 0;
result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
output_data, output_stride_in_bytes, output_data, output_stride_in_bytes,
alpha_channel, flags, type, alpha_channel, flags, type,
edge_horizontal, edge_vertical, edge_horizontal, edge_vertical,
colorspace, extra_memory, memory_required); colorspace, extra_memory, memory_required);
@ -2499,7 +2500,7 @@ STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels
STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context) void *alloc_context)
{ {
return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
@ -2511,7 +2512,7 @@ STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context) void *alloc_context)
{ {
return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
@ -2524,7 +2525,7 @@ STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int
STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context) void *alloc_context)
{ {
return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
@ -2538,7 +2539,7 @@ STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype, stbir_datatype datatype,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context) stbir_colorspace space, void *alloc_context)
{ {
@ -2553,7 +2554,7 @@ STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype, stbir_datatype datatype,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context, stbir_colorspace space, void *alloc_context,
float x_scale, float y_scale, float x_scale, float y_scale,
@ -2574,7 +2575,7 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype, stbir_datatype datatype,
int num_channels, int alpha_channel, int flags, int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context, stbir_colorspace space, void *alloc_context,
float s0, float t0, float s1, float t1) float s0, float t0, float s1, float t1)
@ -2593,38 +2594,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE A - MIT License ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 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 of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions: so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org) ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain. This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 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, software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means. commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this 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 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 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 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 overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law. this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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 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 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. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*/ */

View file

@ -1,4 +1,4 @@
/* stb_image_write - v1.13 - public domain - http://nothings.org/stb /* stb_image_write - v1.14 - public domain - http://nothings.org/stb
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@ -105,7 +105,7 @@ USAGE:
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
data, set the global variable 'stbi_write_tga_with_rle' to 0. data, set the global variable 'stbi_write_tga_with_rle' to 0.
JPEG does ignore alpha channels in input data; quality is between 1 and 100. JPEG does ignore alpha channels in input data; quality is between 1 and 100.
Higher quality looks better but results in a bigger image. Higher quality looks better but results in a bigger image.
JPEG baseline (no JPEG progressive). JPEG baseline (no JPEG progressive).
@ -113,7 +113,7 @@ USAGE:
CREDITS: CREDITS:
Sean Barrett - PNG/BMP/TGA Sean Barrett - PNG/BMP/TGA
Baldur Karlsson - HDR Baldur Karlsson - HDR
Jean-Sebastien Guay - TGA monochrome Jean-Sebastien Guay - TGA monochrome
Tim Kelsey - misc enhancements Tim Kelsey - misc enhancements
@ -247,17 +247,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC #ifdef STB_IMAGE_WRITE_STATIC
static int stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression_level = 8; static int stbi_write_png_compression_level = 8;
static int stbi_write_tga_with_rle = 1; static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1; static int stbi_write_force_png_filter = -1;
#else #else
int stbi_write_png_compression_level = 8; int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1; int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1; int stbi_write_force_png_filter = -1;
#endif #endif
static int stbi__flip_vertically_on_write = 0;
STBIWDEF void stbi_flip_vertically_on_write(int flag) STBIWDEF void stbi_flip_vertically_on_write(int flag)
{ {
stbi__flip_vertically_on_write = flag; stbi__flip_vertically_on_write = flag;
@ -306,7 +306,7 @@ static FILE *stbiw__fopen(char const *filename, char const *mode)
wchar_t wFilename[1024]; wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
return 0; return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
return 0; return 0;
@ -774,7 +774,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
#ifndef STBIW_ZLIB_COMPRESS #ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2) #define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1] #define stbiw__sbn(a) stbiw__sbraw(a)[1]
@ -1044,13 +1044,13 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int
int type = mymap[filter_type]; int type = mymap[filter_type];
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
if (type==0) { if (type==0) {
memcpy(line_buffer, z, width*n); memcpy(line_buffer, z, width*n);
return; return;
} }
// first loop isn't optimized since it's just one pixel // first loop isn't optimized since it's just one pixel
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
switch (type) { switch (type) {
case 1: line_buffer[i] = z[i]; break; case 1: line_buffer[i] = z[i]; break;
@ -1271,26 +1271,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
bits[0] = val & ((1<<bits[1])-1); bits[0] = val & ((1<<bits[1])-1);
} }
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) { static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] }; const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] }; const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
int dataOff, i, diff, end0pos; int dataOff, i, j, n, diff, end0pos, x, y;
int DU[64]; int DU[64];
// DCT rows // DCT rows
for(dataOff=0; dataOff<64; dataOff+=8) { for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]); stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
} }
// DCT columns // DCT columns
for(dataOff=0; dataOff<8; ++dataOff) { for(dataOff=0; dataOff<8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]); stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],
&CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);
} }
// Quantize/descale/zigzag the coefficients // Quantize/descale/zigzag the coefficients
for(i=0; i<64; ++i) { for(y = 0, j=0; y < 8; ++y) {
float v = CDU[i]*fdtbl[i]; for(x = 0; x < 8; ++x,++j) {
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); float v;
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? i = y*du_stride+x;
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); v = CDU[i]*fdtbl[j];
// DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
}
} }
// Encode DC // Encode DC
@ -1405,10 +1410,10 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
int row, col, i, k; int row, col, i, k, subsample;
float fdtbl_Y[64], fdtbl_UV[64]; float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[64]; unsigned char YTable[64], UVTable[64];
@ -1417,6 +1422,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
} }
quality = quality ? quality : 90; quality = quality ? quality : 90;
subsample = quality <= 90 ? 1 : 0;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2; quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
@ -1439,7 +1445,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
s->func(s->context, (void*)head0, sizeof(head0)); s->func(s->context, (void*)head0, sizeof(head0));
s->func(s->context, (void*)YTable, sizeof(YTable)); s->func(s->context, (void*)YTable, sizeof(YTable));
stbiw__putc(s, 1); stbiw__putc(s, 1);
@ -1462,36 +1468,74 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
// Encode 8x8 macroblocks // Encode 8x8 macroblocks
{ {
static const unsigned short fillBits[] = {0x7F, 7}; static const unsigned short fillBits[] = {0x7F, 7};
const unsigned char *imageData = (const unsigned char *)data;
int DCY=0, DCU=0, DCV=0; int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0; int bitBuf=0, bitCnt=0;
// comp == 2 is grey+alpha (alpha is ignored) // comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
const unsigned char *dataR = (const unsigned char *)data;
const unsigned char *dataG = dataR + ofsG;
const unsigned char *dataB = dataR + ofsB;
int x, y, pos; int x, y, pos;
for(y = 0; y < height; y += 8) { if(subsample) {
for(x = 0; x < width; x += 8) { for(y = 0; y < height; y += 16) {
float YDU[64], UDU[64], VDU[64]; for(x = 0; x < width; x += 16) {
for(row = y, pos = 0; row < y+8; ++row) { float Y[256], U[256], V[256];
// row >= height => use last input row for(row = y, pos = 0; row < y+16; ++row) {
int clamped_row = (row < height) ? row : height - 1; // row >= height => use last input row
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; int clamped_row = (row < height) ? row : height - 1;
for(col = x; col < x+8; ++col, ++pos) { int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
float r, g, b; for(col = x; col < x+16; ++col, ++pos) {
// if col >= width => use pixel from last input column // if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp; int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
r = imageData[p+0]; // subsample U,V
g = imageData[p+ofsG]; {
b = imageData[p+ofsB]; float subU[64], subV[64];
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; int yy, xx;
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; for(yy = 0, pos = 0; yy < 8; ++yy) {
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; for(xx = 0; xx < 8; ++xx, ++pos) {
int j = yy*32+xx*2;
subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;
subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;
}
}
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
} }
} }
}
} else {
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float Y[64], U[64], V[64];
for(row = y, pos = 0; row < y+8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
} }
} }
@ -1530,10 +1574,13 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
1.13
1.12
1.11 (2019-08-11) 1.11 (2019-08-11)
1.10 (2019-02-07) 1.10 (2019-02-07)
support utf8 filenames in Windows; fix warnings and platform ifdefs support utf8 filenames in Windows; fix warnings and platform ifdefs
1.09 (2018-02-11) 1.09 (2018-02-11)
fix typo in zlib quality API, improve STB_I_W_STATIC in C++ fix typo in zlib quality API, improve STB_I_W_STATIC in C++
1.08 (2018-01-29) 1.08 (2018-01-29)
@ -1582,38 +1629,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE A - MIT License ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 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 of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions: so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org) ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain. This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 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, software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means. commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this 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 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 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 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 overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law. this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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 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 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. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*/ */

View file

@ -1,4 +1,4 @@
// stb_perlin.h - v0.4 - perlin noise // stb_perlin.h - v0.5 - perlin noise
// public domain single-file C implementation by Sean Barrett // public domain single-file C implementation by Sean Barrett
// //
// LICENSE // LICENSE
@ -47,9 +47,9 @@
// //
// Fractal Noise: // Fractal Noise:
// //
// Three common fractal noise functions are included, which produce // Three common fractal noise functions are included, which produce
// a wide variety of nice effects depending on the parameters // a wide variety of nice effects depending on the parameters
// provided. Note that each function will call stb_perlin_noise3 // provided. Note that each function will call stb_perlin_noise3
// 'octaves' times, so this parameter will affect runtime. // 'octaves' times, so this parameter will affect runtime.
// //
// float stb_perlin_ridge_noise3(float x, float y, float z, // float stb_perlin_ridge_noise3(float x, float y, float z,
@ -66,7 +66,7 @@
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output) // lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
// gain = 0.5 -- relative weighting applied to each successive octave // gain = 0.5 -- relative weighting applied to each successive octave
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure // offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
// //
// //
// Contributors: // Contributors:
// Jack Mott - additional noise functions // Jack Mott - additional noise functions
@ -78,6 +78,7 @@
extern "C" { extern "C" {
#endif #endif
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap); extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed);
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves); extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves); extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves); extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
@ -94,41 +95,41 @@ extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wra
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/ // Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
static unsigned char stb__perlin_randtab[512] = static unsigned char stb__perlin_randtab[512] =
{ {
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
// and a second copy so we don't need an extra mask or static initializer // and a second copy so we don't need an extra mask or static initializer
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
}; };
// perlin's gradient has 12 cases so some get used 1/16th of the time // perlin's gradient has 12 cases so some get used 1/16th of the time
@ -297,7 +298,7 @@ float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float g
float frequency = 1.0f; float frequency = 1.0f;
float amplitude = 1.0f; float amplitude = 1.0f;
float sum = 0.0f; float sum = 0.0f;
for (i = 0; i < octaves; i++) { for (i = 0; i < octaves; i++) {
sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude; sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
frequency *= lacunarity; frequency *= lacunarity;
@ -312,7 +313,7 @@ float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity,
float frequency = 1.0f; float frequency = 1.0f;
float amplitude = 1.0f; float amplitude = 1.0f;
float sum = 0.0f; float sum = 0.0f;
for (i = 0; i < octaves; i++) { for (i = 0; i < octaves; i++) {
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude; float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
sum += (float) fabs(r); sum += (float) fabs(r);
@ -390,38 +391,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE A - MIT License ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 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 of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions: so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org) ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain. This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 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, software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means. commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this 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 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 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 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 overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law. this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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 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 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. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*/ */

View file

@ -28,7 +28,7 @@
// Minor features // Minor features
// Martins Mozeiko // Martins Mozeiko
// github:IntellectualKitty // github:IntellectualKitty
// //
// Bugfixes / warning fixes // Bugfixes / warning fixes
// Jeremy Jaussaud // Jeremy Jaussaud
// Fabian Giesen // Fabian Giesen
@ -432,7 +432,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
} }
} }
tail = tail->next; tail = tail->next;
} }
} }
fr.prev_link = best; fr.prev_link = best;
@ -591,38 +591,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE A - MIT License ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 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 of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions: so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org) ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain. This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 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, software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means. commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this 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 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 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 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 overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law. this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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 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 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. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*/ */

View file

@ -1,5 +1,14 @@
// stb_truetype.h - v1.22 - public domain // stb_truetype.h - v1.24 - public domain
// authored from 2009-2019 by Sean Barrett / RAD Game Tools // authored from 2009-2020 by Sean Barrett / RAD Game Tools
//
// =======================================================================
//
// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
//
// This library does no range checking of the offsets found in the file,
// meaning an attacker can use it to read arbitrary memory.
//
// =======================================================================
// //
// This library processes TrueType files: // This library processes TrueType files:
// parse files // parse files
@ -32,11 +41,11 @@
// Daniel Ribeiro Maciel // Daniel Ribeiro Maciel
// //
// Bug/warning reports/fixes: // Bug/warning reports/fixes:
// "Zer" on mollyrocket Fabian "ryg" Giesen // "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe
// Cass Everitt Martins Mozeiko // Cass Everitt Martins Mozeiko github:aloucks
// stoiko (Haemimont Games) Cap Petschulat // stoiko (Haemimont Games) Cap Petschulat github:oyvindjam
// Brian Hook Omar Cornut // Brian Hook Omar Cornut github:vassvik
// Walter van Niftrik github:aloucks // Walter van Niftrik Ryan Griege
// David Gow Peter LaValle // David Gow Peter LaValle
// David Given Sergey Popov // David Given Sergey Popov
// Ivan-Assen Ivanov Giumo X. Clanjor // Ivan-Assen Ivanov Giumo X. Clanjor
@ -44,13 +53,14 @@
// Johan Duparc Thomas Fields // Johan Duparc Thomas Fields
// Hou Qiming Derek Vinyard // Hou Qiming Derek Vinyard
// Rob Loach Cort Stratton // Rob Loach Cort Stratton
// Kenney Phillis Jr. github:oyvindjam // Kenney Phillis Jr. Brian Costabile
// Brian Costabile github:vassvik // Ken Voskuil (kaesve)
// Ken Voskuil (kaesve) Ryan Griege //
//
// VERSION HISTORY // VERSION HISTORY
// //
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined // 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.21 (2019-02-25) fix warning
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() // 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod // 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
@ -210,7 +220,7 @@
// //
// Advancing for the next character: // Advancing for the next character:
// Call GlyphHMetrics, and compute 'current_point += SF * advance'. // Call GlyphHMetrics, and compute 'current_point += SF * advance'.
// //
// //
// ADVANCED USAGE // ADVANCED USAGE
// //
@ -335,7 +345,7 @@ int main(int argc, char **argv)
} }
return 0; return 0;
} }
#endif #endif
// //
// Output: // Output:
// //
@ -349,9 +359,9 @@ int main(int argc, char **argv)
// :@@. M@M // :@@. M@M
// @@@o@@@@ // @@@o@@@@
// :M@@V:@@. // :M@@V:@@.
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// Complete program: print "Hello World!" banner, with bugs // Complete program: print "Hello World!" banner, with bugs
// //
#if 0 #if 0
@ -652,7 +662,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, cons
// Calling these functions in sequence is roughly equivalent to calling // Calling these functions in sequence is roughly equivalent to calling
// stbtt_PackFontRanges(). If you more control over the packing of multiple // 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 // 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 // at the source to of stbtt_PackFontRanges() and create a custom version
// using these functions, e.g. call GatherRects multiple times, // using these functions, e.g. call GatherRects multiple times,
// building up a single array of rects, then call PackRects once, // building up a single array of rects, then call PackRects once,
// then call RenderIntoRects repeatedly. This may result in a // then call RenderIntoRects repeatedly. This may result in a
@ -704,7 +714,7 @@ struct stbtt_fontinfo
int numGlyphs; // number of glyphs, needed for range checking int numGlyphs; // number of glyphs, needed for range checking
int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf 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 index_map; // a cmap mapping for our chosen character encoding
int indexToLocFormat; // format needed to map from glyph index to glyph int indexToLocFormat; // format needed to map from glyph index to glyph
@ -787,6 +797,18 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1,
STBTT_DEF int stbtt_GetGlyphBox(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);
// as above, but takes one or more glyph indices for greater efficiency // 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)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -831,6 +853,11 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
// frees the data allocated above // frees the data allocated above
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
// fills svg with the character's SVG data.
// returns data size or 0 if SVG not found.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// BITMAP RENDERING // BITMAP RENDERING
@ -960,7 +987,7 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa
// and computing from that can allow drop-out prevention). // and computing from that can allow drop-out prevention).
// //
// The algorithm has not been optimized at all, so expect it to be slow // The algorithm has not been optimized at all, so expect it to be slow
// if computing lots of characters or very large sizes. // if computing lots of characters or very large sizes.
@ -1332,6 +1359,22 @@ static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
return stbtt__cff_get_index(&cff); 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) static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
{ {
stbtt_uint32 cmap, t; stbtt_uint32 cmap, t;
@ -1411,6 +1454,8 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
else else
info->numGlyphs = 0xffff; info->numGlyphs = 0xffff;
info->svg = -1;
// find a cmap encoding table we understand *now* to avoid searching // find a cmap encoding table we understand *now* to avoid searching
// later. (todo: could make this installable) // later. (todo: could make this installable)
// the same regardless of glyph. // the same regardless of glyph.
@ -1717,7 +1762,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
if (i != 0) if (i != 0)
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
// now start the new one // now start the new one
start_off = !(flags & 1); start_off = !(flags & 1);
if (start_off) { if (start_off) {
// if we start off with an off-curve point, then when we need to find a point on the curve // if we start off with an off-curve point, then when we need to find a point on the curve
@ -1759,7 +1804,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
} }
} }
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
} else if (numberOfContours == -1) { } else if (numberOfContours < 0) {
// Compound shapes. // Compound shapes.
int more = 1; int more = 1;
stbtt_uint8 *comp = data + g + 10; stbtt_uint8 *comp = data + g + 10;
@ -1770,7 +1815,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
int comp_num_verts = 0, i; int comp_num_verts = 0, i;
stbtt_vertex *comp_verts = 0, *tmp = 0; stbtt_vertex *comp_verts = 0, *tmp = 0;
float mtx[6] = {1,0,0,1,0,0}, m, n; float mtx[6] = {1,0,0,1,0,0}, m, n;
flags = ttSHORT(comp); comp+=2; flags = ttSHORT(comp); comp+=2;
gidx = ttSHORT(comp); comp+=2; gidx = ttSHORT(comp); comp+=2;
@ -1800,7 +1845,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
} }
// Find transformation scales. // Find transformation scales.
m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
@ -1836,9 +1881,6 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
// More components ? // More components ?
more = flags & (1<<5); more = flags & (1<<5);
} }
} else if (numberOfContours < 0) {
// @TODO other compound variations?
STBTT_assert(0);
} else { } else {
// numberOfCounters == 0, do nothing // numberOfCounters == 0, do nothing
} }
@ -2267,6 +2309,48 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde
} }
} }
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) static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
{ {
stbtt_uint8 *data = info->data + info->kern; stbtt_uint8 *data = info->data + info->kern;
@ -2603,6 +2687,45 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
STBTT_free(v, info->userdata); 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<numEntries; i++) {
stbtt_uint8 *svg_doc = svg_docs + (12 * i);
if ((gl >= 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 // antialiasing software rasterizer
@ -2728,7 +2851,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
STBTT_assert(z != NULL); STBTT_assert(z != NULL);
if (!z) return z; if (!z) return z;
// round dx down to avoid overshooting // round dx down to avoid overshooting
if (dxdy < 0) if (dxdy < 0)
z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
@ -2806,7 +2929,7 @@ static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__ac
} }
} }
} }
e = e->next; e = e->next;
} }
} }
@ -3534,7 +3657,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info
{ {
int ix0,iy0,ix1,iy1; int ix0,iy0,ix1,iy1;
stbtt__bitmap gbm; stbtt__bitmap gbm;
stbtt_vertex *vertices; stbtt_vertex *vertices;
int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
if (scale_x == 0) scale_x = scale_y; if (scale_x == 0) scale_x = scale_y;
@ -3557,7 +3680,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info
if (height) *height = gbm.h; if (height) *height = gbm.h;
if (xoff ) *xoff = ix0; if (xoff ) *xoff = ix0;
if (yoff ) *yoff = iy0; if (yoff ) *yoff = iy0;
if (gbm.w && gbm.h) { if (gbm.w && gbm.h) {
gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
if (gbm.pixels) { if (gbm.pixels) {
@ -3568,7 +3691,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info
} }
STBTT_free(vertices, info->userdata); STBTT_free(vertices, info->userdata);
return gbm.pixels; 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) 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)
{ {
@ -3580,7 +3703,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigne
int ix0,iy0; int ix0,iy0;
stbtt_vertex *vertices; stbtt_vertex *vertices;
int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
stbtt__bitmap gbm; stbtt__bitmap gbm;
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
gbm.pixels = output; gbm.pixels = output;
@ -3602,7 +3725,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *
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) 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); 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_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)
{ {
@ -3617,7 +3740,7 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns
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) 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); 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_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)
{ {
@ -3742,7 +3865,7 @@ static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *no
con->y = 0; con->y = 0;
con->bottom_y = 0; con->bottom_y = 0;
STBTT__NOTUSED(nodes); STBTT__NOTUSED(nodes);
STBTT__NOTUSED(num_nodes); STBTT__NOTUSED(num_nodes);
} }
static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
@ -4137,7 +4260,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char
n = 0; n = 0;
for (i=0; i < num_ranges; ++i) for (i=0; i < num_ranges; ++i)
n += ranges[i].num_chars; n += ranges[i].num_chars;
rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
if (rects == NULL) if (rects == NULL)
return 0; return 0;
@ -4148,7 +4271,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char
n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
stbtt_PackFontRangesPackRects(spc, rects, n); stbtt_PackFontRangesPackRects(spc, rects, n);
return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
STBTT_free(rects, spc->user_allocator_context); STBTT_free(rects, spc->user_allocator_context);
@ -4309,7 +4432,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
int x1 = (int) verts[i ].x, y1 = (int) verts[i ].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)) { 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; float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x) if (x_inter < x)
winding += (y0 < y1) ? 1 : -1; winding += (y0 < y1) ? 1 : -1;
} }
} }
@ -4335,7 +4458,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
y1 = (int)verts[i ].y; y1 = (int)verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { 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; float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x) if (x_inter < x)
winding += (y0 < y1) ? 1 : -1; winding += (y0 < y1) ? 1 : -1;
} }
} else { } else {
@ -4347,7 +4470,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
if (hits[1][0] < 0) if (hits[1][0] < 0)
winding += (hits[1][1] < 0 ? -1 : 1); winding += (hits[1][1] < 0 ? -1 : 1);
} }
} }
} }
} }
return winding; return winding;
@ -4423,7 +4546,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
// invert for y-downwards bitmaps // invert for y-downwards bitmaps
scale_y = -scale_y; scale_y = -scale_y;
{ {
int x,y,i,j; int x,y,i,j;
float *precompute; float *precompute;
@ -4572,7 +4695,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
STBTT_free(verts, info->userdata); STBTT_free(verts, info->userdata);
} }
return data; 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) 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)
{ {
@ -4590,7 +4713,7 @@ STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
// //
// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string // 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) static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
{ {
stbtt_int32 i=0; stbtt_int32 i=0;
@ -4629,7 +4752,7 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, s
return i; return i;
} }
static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) 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); return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
} }
@ -4758,7 +4881,7 @@ STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
{ {
return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
} }
STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
@ -4851,38 +4974,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE A - MIT License ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 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 of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions: so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org) ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain. This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 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, software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means. commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this 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 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 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 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 overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law. this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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 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 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. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*/ */