Add stb libraries (image+image_write, rect_pack, truetype)

This commit is contained in:
gingerBill
2021-09-14 17:54:50 +01:00
parent c2707618d9
commit 7189625cf5
16 changed files with 16216 additions and 4 deletions

View File

@@ -3,7 +3,7 @@
setlocal EnableDelayedExpansion
for /f "usebackq tokens=1,2 delims=,=- " %%i in (`wmic os get LocalDateTime /value`) do @if %%i==LocalDateTime (
set CURR_DATE_TIME=%%j
set CURR_DATE_TIME=%%j
)
set curr_year=%CURR_DATE_TIME:~0,4%
@@ -23,9 +23,9 @@ if "%1" == "1" (
:: Normal = 0, CI Nightly = 1
if "%2" == "1" (
set nightly=1
set nightly=1
) else (
set nightly=0
set nightly=0
)
set odin_version_raw="dev-%curr_year%-%curr_month%"
@@ -69,8 +69,11 @@ del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.cpp" "src\libtommath.cpp" /link %linker_settings% -OUT:%exe_name%
if %errorlevel% neq 0 goto end_of_build
call build_vendor.bat
if %errorlevel% neq 0 goto end_of_build
if %release_mode% EQU 0 odin run examples/demo
del *.obj > NUL 2> NUL

107
vendor/stb/image/stb_image.odin vendored Normal file
View File

@@ -0,0 +1,107 @@
package stb_image
import c "core:c/libc"
#assert(size_of(c.int) == size_of(b32))
when ODIN_OS == "windows" { foreign import stbi "../lib/stb_image.lib" }
when ODIN_OS == "linux" { foreign import stbi "../lib/stb_image.a" }
#assert(size_of(b32) == size_of(c.int));
//
// load image by filename, open file, or memory buffer
//
Io_Callbacks :: struct {
read: proc "c" (user: rawptr, data: [^]byte, size: c.int) -> c.int, // fill 'data' with 'size' u8s. return number of u8s actually read
skip: proc "c" (user: rawptr, n: c.int), // skip the next 'n' u8s, or 'unget' the last -n u8s if negative
eof: proc "c" (user: rawptr) -> c.int, // returns nonzero if we are at end of file/data
}
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbi {
////////////////////////////////////
//
// 8-bits-per-channel interface
//
load :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_gif_from_memory :: proc(buffer: [^]byte, len: c.int, delays: ^[^]c.int, x, y, z, comp: ^c.int, req_comp: c.int) -> [^]byte ---
////////////////////////////////////
//
// 16-bits-per-channel interface
//
load_16 :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_callbacks :: proc(clbk: ^Io_Callbacks, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
////////////////////////////////////
//
// float-per-channel interface
//
loadf :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
hdr_to_ldr_gamma :: proc(gamma: f32) ---
hdr_to_ldr_scale :: proc(scale: f32) ---
ldr_to_hdr_gamma :: proc(gamma: f32) ---
ldr_to_hdr_scale :: proc(scale: f32) ---
is_hdr_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr) -> c.int ---
is_hdr_from_memory :: proc(buffer: [^]byte, len: c.int) -> c.int ---
is_hdr :: proc(filename: cstring) -> c.int ---
is_hdr_from_file :: proc(f: ^c.FILE) -> c.int ---
// get a VERY brief reason for failure
// NOT THREADSAFE
failure_reason :: proc() -> cstring ---
// free the loaded image -- this is just free()
image_free :: proc(retval_from_load: rawptr) ---
// get image dimensions & components without fully decoding
info :: proc(filename: cstring, x, y, comp: ^c.int) -> c.int ---
info_from_file :: proc(f: ^c.FILE, x, y, comp: ^c.int) -> c.int ---
info_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, comp: ^c.int) -> c.int ---
info_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, comp: ^c.int) -> c.int ---
is_16_bit :: proc(filename: cstring) -> b32 ---
is_16_bit_from_file :: proc(f: ^c.FILE) -> b32 ---
// for image formats that explicitly notate that they have premultiplied alpha,
// we just return the colors as stored in the file. set this flag to force
// unpremultiplication. results are undefined if the unpremultiply overflow.
set_unpremultiply_on_load :: proc (flag_true_if_should_unpremultiply: c.int) ---
// indicate whether we should process iphone images back to canonical format,
// or just pass them through "as-is"
convert_iphone_png_to_rgb :: proc(flag_true_if_should_convert: c.int) ---
// flip the image vertically, so the first pixel in the output array is the bottom left
set_flip_vertically_on_load :: proc(flag_true_if_should_flip: c.int) ---
// 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
set_unpremultiply_on_load_thread :: proc(flag_true_if_should_unpremultiply: b32) ---
convert_iphone_png_to_rgb_thread :: proc(flag_true_if_should_convert: b32) ---
set_flip_vertically_on_load_thread :: proc(flag_true_if_should_flip: b32) ---
// ZLIB client - used by PNG, available for other purposes
zlib_decode_malloc_guesssize :: proc(buffer: [^]byte, len: c.int, initial_size: c.int, outlen: ^c.int) -> [^]byte ---
zlib_decode_malloc_guesssize_headerflag :: proc(buffer: [^]byte, len: c.int, initial_size: c.int, outlen: ^c.int, parse_header: b32) -> [^]byte ---
zlib_decode_malloc :: proc(buffer: [^]byte, len: c.int, outlen: ^c.int) -> [^]byte ---
zlib_decode_buffer :: proc(obuffer: [^]byte, olen: c.int, ibuffer: [^]byte, ilen: c.int) -> c.int ---
zlib_decode_noheader_malloc :: proc(buffer: [^]byte, len: c.int, outlen: ^c.int) -> [^]byte ---
zlib_decode_noheader_buffer :: proc(obuffer: [^]byte, olen: c.int, ibuffer: [^]byte, ilen: c.int) -> c.int ---
}

26
vendor/stb/image/stb_image_write.odin vendored Normal file
View File

@@ -0,0 +1,26 @@
package stb_image
import c "core:c/libc"
when ODIN_OS == "windows" { foreign import stbiw "../lib/stb_image_write.lib" }
when ODIN_OS == "linux" { foreign import stbiw "../lib/stb_image_write.a" }
write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int);
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbiw {
write_png :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
write_bmp :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
write_tga :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
write_hdr :: proc(filename: cstring, w, h, comp: c.int, data: [^]f32) -> c.int ---
write_jpg :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, quality: c.int /*0..=100*/) -> c.int ---
write_png_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
write_bmp_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr) -> c.int ---
write_tga_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr) -> c.int ---
write_hdr_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: [^]f32) -> c.int ---
write_jpg_to_func :: proc(func: write_func, ctx: rawptr, x, y, comp: c.int, data: rawptr, quality: c.int /*0..=100*/) -> c.int ---
flip_vertically_on_write :: proc(flip_boolean: b32) ---
}

0
vendor/stb/lib/.gitkeep vendored Normal file
View File

112
vendor/stb/rect_pack/stb_rect_pack.odin vendored Normal file
View File

@@ -0,0 +1,112 @@
package stb_rect_pack
import c "core:c/libc"
#assert(size_of(b32) == size_of(c.int))
when ODIN_OS == "windows" { foreign import lib "../lib/stb_rect_pack.lib" }
when ODIN_OS == "linux" { foreign import lib "../lib/stb_rect_pack.a" }
Coord :: distinct c.int
_MAXVAL :: max(Coord)
Rect :: struct {
// reserved for your use:
id: c.int,
// input:
w, h: Coord,
// output:
x, y: Coord,
was_packed: b32, // non-zero if valid packing
}
Heuristic :: enum c.int {
Skyline_default = 0,
Skyline_BL_sortHeight = Skyline_default,
Skyline_BF_sortHeight,
}
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
Node :: struct {
x, y: Coord,
next: ^Node,
}
Context :: struct {
width: c.int,
height: c.int,
align: c.int,
init_mode: c.int,
heuristic: Heuristic,
num_nodes: c.int,
active_head: ^Node,
free_head: ^Node,
extra: [2]Node, // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
}
@(default_calling_convention="c", link_prefix="stbrp_")
foreign lib {
// Assign packed locations to rectangles. The rectangles are of type
// 'Rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
pack_rects :: proc(ctx: ^Context, rects: [^]Rect, num_rects: c.int) -> c.int ---
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call setup_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
init_target :: proc(ctx: ^Context, width, height: c.int, nodes: [^]Node, num_nodes: c.int) ---
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
setup_allow_out_of_mem :: proc(ctx: ^Context, allow_out_of_mem: b32) ---
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
setup_heuristic :: proc(ctx: ^Context, heuristic: Heuristic) ---
}

12
vendor/stb/src/Makefile vendored Normal file
View File

@@ -0,0 +1,12 @@
all:
mkdir -p ../lib
gcc -c -O2 -march=native -Os -fPIC stb_image.c stb_image_write.c stb_truetype.c stb_rect_pack.c
ar rcs ../lib/stb_image.a stb_image.o
ar rcs ../lib/stb_image_write.a stb_image_write.o
ar rcs ../lib/stb_truetype.a stb_truetype.o
ar rcs ../lib/stb_rect_pack.a stb_rect_pack.o
#gcc -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o
#gcc -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o
#gcc -fPIC -shared -Wl,-soname=stb_truetype.so -o ../lib/stb_truetype.so stb_image_truetype.o
#gcc -fPIC -shared -Wl,-soname=stb_rect_pack.so -o ../lib/stb_rect_pack.so stb_rect_packl.o
rm *.o

11
vendor/stb/src/build.bat vendored Normal file
View File

@@ -0,0 +1,11 @@
@echo off
if not exist "..\lib" mkdir ..\lib
cl -nologo -MT -TC -O2 -c stb_image.c stb_image_write.c stb_truetype.c stb_rect_pack.c
lib -nologo stb_image.obj -out:..\lib\stb_image.lib
lib -nologo stb_image_write.obj -out:..\lib\stb_image_write.lib
lib -nologo stb_truetype.obj -out:..\lib\stb_truetype.lib
lib -nologo stb_rect_pack.obj -out:..\lib\stb_rect_pack.lib
del stb_image.obj stb_image_write.obj stb_truetype.obj stb_rect_pack.obj

2
vendor/stb/src/stb_image.c vendored Normal file
View File

@@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

7897
vendor/stb/src/stb_image.h vendored Normal file

File diff suppressed because it is too large Load Diff

2
vendor/stb/src/stb_image_write.c vendored Normal file
View File

@@ -0,0 +1,2 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

1724
vendor/stb/src/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load Diff

2
vendor/stb/src/stb_rect_pack.c vendored Normal file
View File

@@ -0,0 +1,2 @@
#define STB_RECT_PACK_IMPLEMENTATION
#include "stb_rect_pack.h"

623
vendor/stb/src/stb_rect_pack.h vendored Normal file
View File

@@ -0,0 +1,623 @@
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Before #including,
//
// #define STB_RECT_PACK_IMPLEMENTATION
//
// in the file that you want to have the implementation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
//
// Version history:
//
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
typedef int stbrp_coord;
#define STBRP__MAXVAL 0x7fffffff
// Mostly for internal use, but this is the maximum supported coordinate value.
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
context->extra[1].y = (1<<30);
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
// if it can't possibly fit, bail immediately
if (width > c->width || height > c->height) {
fr.prev_link = NULL;
fr.x = fr.y = 0;
return fr;
}
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
STBRP_ASSERT(y <= best_y);
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
int count=0;
cur = context->active_head;
while (cur) {
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

5
vendor/stb/src/stb_truetype.c vendored Normal file
View File

@@ -0,0 +1,5 @@
#define STB_RECT_PACK_IMPLEMENTATION
#include "stb_rect_pack.h"
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"

5077
vendor/stb/src/stb_truetype.h vendored Normal file

File diff suppressed because it is too large Load Diff

609
vendor/stb/truetype/stb_truetype.odin vendored Normal file
View File

@@ -0,0 +1,609 @@
package stb_truetype
import c "core:c/libc"
import stbrp "vendor:stb/rect_pack"
when ODIN_OS == "windows" { foreign import stbtt "../lib/stb_truetype.lib" }
when ODIN_OS == "linux" { foreign import stbtt "../lib/stb_truetype.a" }
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
////
//// INTERFACE
////
////
#assert(size_of(c.int) == size_of(rune));
#assert(size_of(c.int) == size_of(b32));
// private structure
_buf :: struct {
data: [^]u8,
cursor, size: c.int,
}
//////////////////////////////////////////////////////////////////////////////
//
// TEXTURE BAKING API
//
// If you use this API, you only have to call two functions ever.
//
bakedchar :: struct {
x0, y0, x1, y1: u16, // coordinates of bbox in bitmap
xoff, yoff, xadvance: f32,
}
aligned_quad :: struct {
x0, y0, s0, t0: f32, // top-left
x1, y1, s1, t1: f32, // bottom-right
}
// bindings
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// if return is positive, the first unused row of the bitmap
// if return is negative, returns the negative of the number of characters that fit
// if return is 0, no characters fit and no rows were used
// This uses a very crappy packing.
BakeFontBitmap :: proc(data: [^]byte, offset: c.int, // font location (use offset=0 for plain .ttf)
pixel_height: f32, // height of font in pixels
pixels: [^]byte, pw, ph: c.int, // bitmap to be filled in
first_char, num_chars: c.int, // characters to bake
chardata: [^]bakedchar, // you allocate this, it's num_chars long
) -> c.int ---
// Call GetBakedQuad with char_index = 'character - first_char', and it
// creates the quad you need to draw and advances the current position.
//
// The coordinate system used assumes y increases downwards.
//
// Characters will extend both above and below the current position;
// see discussion of "BASELINE" above.
//
// It's inefficient; you might want to c&p it and optimize it.
GetBakedQuad :: proc(chardata: ^bakedchar, pw, ph: c.int, // same data as above
char_index: c.int, // character to display
xpos, ypos: ^f32, // pointers to current position in screen pixel space
q: ^aligned_quad, // output: quad to draw
opengl_fillrule: b32, // true if opengl fill rule; false if DX9 or earlier
) ---
// Query the font vertical metrics without having to create a font first.
GetScaledFontVMetrics :: proc(fontdata: [^]byte, index: c.int, size: f32, ascent, descent, lineGap: ^f32) ---
}
//////////////////////////////////////////////////////////////////////////////
//
// NEW TEXTURE BAKING API
//
// This provides options for packing multiple fonts into one atlas, not
// perfectly but better than nothing.
packedchar :: struct {
x0, y0, x1, y1: u16,
xoff, yoff, xadvance: f32,
xoff2, yoff2: f32,
}
pack_range :: struct {
font_size: f32,
first_unicode_codepoint_in_range: c.int,
array_of_unicode_codepoints: [^]rune,
num_chars: c.int,
chardata_for_range: ^packedchar,
_, _: u8, // used internally to store oversample info
}
pack_context :: struct {
user_allocator_context, pack_info: rawptr,
width, height, stride_in_bytes, padding: c.int,
h_oversample, v_oversample: u32,
pixels: [^]u8,
nodes: rawptr,
};
POINT_SIZE :: #force_inline proc(x: $T) -> T { return -x; } // @NOTE: this was a macro
// bindings
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// Initializes a packing context stored in the passed-in stbtt_pack_context.
// Future calls using this context will pack characters into the bitmap passed
// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
// the distance from one row to the next (or 0 to mean they are packed tightly
// together). "padding" is the amount of padding to leave between each
// character (normally you want '1' for bitmaps you'll use as textures with
// bilinear filtering).
//
// Returns 0 on failure, 1 on success.
PackBegin :: proc(spc: ^pack_context, pixels: [^]byte, width, height, stride_in_bytes, padding: c.int, alloc_context: rawptr) -> c.int ---
// Cleans up the packing context and frees all memory.
PackEnd :: proc(spc: ^pack_context) ---
// Creates character bitmaps from the font_index'th font found in fontdata (use
// font_index=0 if you don't know what that is). It creates num_chars_in_range
// bitmaps for characters with unicode values starting at first_unicode_char_in_range
// and increasing. Data for how to render them is stored in chardata_for_range;
// pass these to stbtt_GetPackedQuad to get back renderable quads.
//
// font_size is the full height of the character from ascender to descender,
// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
// by stbtt_ScaleForMappingEmToPixels, wrap the point size in POINT_SIZE()
// and pass that result as 'font_size':
// ..., 20 , ... // font max minus min y is 20 pixels tall
// ..., POINT_SIZE(20), ... // 'M' is 20 pixels tall
PackFontRange :: proc(spc: ^pack_context, fontdata: [^]byte, font_index: c.int, font_size: f32, first_unicode_char_in_range, num_chars_in_range: c.int, chardata_for_range: ^packedchar) -> c.int ---
// Creates character bitmaps from multiple ranges of characters stored in
// ranges. This will usually create a better-packed bitmap than multiple
// calls to stbtt_PackFontRange. Note that you can call this multiple
// times within a single PackBegin/PackEnd.
PackFontRanges :: proc(spc: ^pack_context, fontdata: [^]byte, font_index: c.int, ranges: [^]pack_range, num_ranges: c.int) -> c.int ---
// Oversampling a font increases the quality by allowing higher-quality subpixel
// positioning, and is especially valuable at smaller text sizes.
//
// This function sets the amount of oversampling for all following calls to
// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
// pack context. The default (no oversampling) is achieved by h_oversample=1
// and v_oversample=1. The total number of pixels required is
// h_oversample*v_oversample larger than the default; for example, 2x2
// oversampling requires 4x the storage of 1x1. For best results, render
// oversampled textures with bilinear filtering. Look at the readme in
// stb/tests/oversample for information about oversampled fonts
//
// To use with PackFontRangesGather etc., you must set it before calls
// call to PackFontRangesGatherRects.
PackSetOversampling :: proc(spc: ^pack_context, h_oversample, v_oversample: c.uint) ---
// If skip != false, this tells stb_truetype to skip any codepoints for which
// there is no corresponding glyph. If skip=false, which is the default, then
// codepoints without a glyph recived the font's "missing character" glyph,
// typically an empty box by convention.
PackSetSkipMissingCodepoints :: proc(spc: ^pack_context, skip: b32) ---
GetPackedQuad :: proc(chardata: ^packedchar, pw, ph: c.int, // same data as above
char_index: c.int, // character to display
xpos, ypos: ^f32, // pointers to current position in screen pixel space
q: ^aligned_quad, // output: quad to draw
align_to_integer: b32,
) ---
// Calling these functions in sequence is roughly equivalent to calling
// stbtt_PackFontRanges(). If you more control over the packing of multiple
// fonts, or if you want to pack custom data into a font texture, take a look
// at the source to of stbtt_PackFontRanges() and create a custom version
// using these functions, e.g. call GatherRects multiple times,
// building up a single array of rects, then call PackRects once,
// then call RenderIntoRects repeatedly. This may result in a
// better packing than calling PackFontRanges multiple times
// (or it may not).
PackFontRangesGatherRects :: proc(spc: ^pack_context, info: ^fontinfo, ranges: ^pack_range, num_ranges: c.int, rects: [^]stbrp.Rect) -> c.int ---
PackFontRangesPackRects :: proc(spc: ^pack_context, rects: [^]stbrp.Rect, num_rects: c.int) ---
PackFontRangesRenderIntoRects :: proc(spc: ^pack_context, info: ^fontinfo, ranges: ^pack_range, num_ranges: c.int, rects: [^]stbrp.Rect) -> c.int ---
}
//////////////////////////////////////////////////////////////////////////////
//
// FONT LOADING
//
//
fontinfo :: struct {
userdata: rawptr,
data: [^]byte,
fontstart: c.int,
numGlyphs: c.int,
loca, head, glyf, hhea, hmtx, kern: c.int,
index_map: c.int,
indexToLocFormat: c.int,
cff: _buf,
charstrings: _buf,
gsubrs: _buf,
subrs: _buf,
fontdicts: _buf,
fdselect: _buf,
}
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// Given an offset into the file that defines a font, this function builds
// the necessary cached info for the rest of the system. You must allocate
// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
// need to do anything special to free it, because the contents are pure
// value data with no additional data structures. Returns 0 on failure.
InitFont :: proc(info: ^fontinfo, data: ^u8, offset: c.int) -> b32 ---
// This function will determine the number of fonts in a font file. TrueType
// collection (.ttc) files may contain multiple fonts, while TrueType font
// (.ttf) files only contain one font. The number of fonts can be used for
// indexing with the previous function where the index is between zero and one
// less than the total fonts. If an error occurs, -1 is returned.
GetNumberOfFonts :: proc(data: [^]byte) -> b32 ---
// Each .ttf/.ttc file may have more than one font. Each font has a sequential
// index number starting from 0. Call this function to get the font offset for
// a given index; it returns -1 if the index is out of range. A regular .ttf
// file will only define one font and it always be at offset 0, so it will
// return '0' for index 0, and -1 for all other indices.
GetFontOffsetForIndex :: proc(data: [^]byte, index: c.int) -> c.int ---
}
//////////////////////////////////////////////////////////////////////////////
//
// CHARACTER TO GLYPH-INDEX CONVERSION
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// If you're going to perform multiple operations on the same character
// and you want a speed-up, call this function with the character you're
// going to process, then use glyph-based functions instead of the
// codepoint-based functions.
// Returns 0 if the character codepoint is not defined in the font.
FindGlyphIndex :: proc(info: ^fontinfo, unicode_codepoint: rune) -> c.int ---
}
//////////////////////////////////////////////////////////////////////////////
//
// CHARACTER PROPERTIES
//
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// computes a scale factor to produce a font whose "height" is 'pixels' tall.
// Height is measured as the distance from the highest ascender to the lowest
// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
// and computing:
// scale = pixels / (ascent - descent)
// so if you prefer to measure height by the ascent only, use a similar calculation.
ScaleForPixelHeight :: proc(info: ^fontinfo, pixels: f32) -> f32 ---
// computes a scale factor to produce a font whose EM size is mapped to
// 'pixels' tall. This is probably what traditional APIs compute, but
// I'm not positive.
ScaleForMappingEmToPixels :: proc(info: ^fontinfo, pixels: f32) -> f32 ---
// ascent is the coordinate above the baseline the font extends; descent
// is the coordinate below the baseline the font extends (i.e. it is typically negative)
// lineGap is the spacing between one row's descent and the next row's ascent...
// so you should advance the vertical position by "*ascent - *descent + *lineGap"
// these are expressed in unscaled coordinates, so you must multiply by
// the scale factor for a given size
GetFontVMetrics :: proc(info: ^fontinfo, ascent, descent, lineGap: ^c.int) ---
// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
// table (specific to MS/Windows TTF files).
//
// Returns 1 on success (table present), 0 on failure.
GetFontVMetricsOS2 :: proc(info: ^fontinfo, typoAscent, typoDescent, typoLineGap: ^c.int) -> b32 ---
// the bounding box around all possible characters
GetFontBoundingBox :: proc(info: ^fontinfo, x0, y0, x1, y1: ^c.int) ---
// leftSideBearing is the offset from the current horizontal position to the left edge of the character
// advanceWidth is the offset from the current horizontal position to the next horizontal position
// these are expressed in unscaled coordinates
GetCodepointHMetrics :: proc(info: ^fontinfo, codepoint: rune, advanceWidth, leftSideBearing: ^c.int) ---
// an additional amount to add to the 'advance' value between ch1 and ch2
GetCodepointKernAdvance :: proc(info: ^fontinfo, ch1, ch2: rune) -> (advance: c.int) ---
// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
GetCodepointBox :: proc(info: ^fontinfo, codepoint: rune, x0, y0, x1, y1: ^c.int) -> c.int ---
// as above, but takes one or more glyph indices for greater efficiency
GetGlyphHMetrics :: proc(info: ^fontinfo, glyph_index: c.int, advanceWidth, leftSideBearing: ^c.int) ---
GetGlyphKernAdvance :: proc(info: ^fontinfo, glyph1, glyph2: c.int) -> c.int ---
GetGlyphBox :: proc(info: ^fontinfo, glyph_index: c.int, x0, y0, x1, y1: ^c.int) -> c.int ---
}
kerningentry :: struct {
glyph1: rune, // use FindGlyphIndex
glyph2: rune,
advance: c.int,
}
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// 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)
GetKerningTableLength :: proc(info: ^fontinfo) -> c.int ---
GetKerningTable :: proc(info: ^fontinfo, table: [^]kerningentry, table_length: c.int) -> c.int ---
}
//////////////////////////////////////////////////////////////////////////////
//
// GLYPH SHAPES (you probably don't need these, but they have to go before
// the bitmaps for C declaration-order reasons)
//
vmove :: enum c.int {
none,
vmove=1,
vline,
vcurve,
vcubic,
}
vertex_type :: distinct c.short // can't use stbtt_int16 because that's not visible in the header file
vertex :: struct {
x, y, cx, cy, cx1, cy1: vertex_type,
type, padding: byte,
}
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// returns true if nothing is drawn for this glyph
IsGlyphEmpty :: proc(info: ^fontinfo, glyph_index: c.int) -> b32 ---
// returns # of vertices and fills *vertices with the pointer to them
// these are expressed in "unscaled" coordinates
//
// The shape is a series of contours. Each one starts with
// a STBTT_moveto, then consists of a series of mixed
// STBTT_lineto and STBTT_curveto segments. A lineto
// draws a line from previous endpoint to its x,y; a curveto
// draws a quadratic bezier from previous endpoint to
// its x,y, using cx,cy as the bezier control point.
GetCodepointShape :: proc(info: ^fontinfo, unicode_codepoint: rune, vertices: ^[^]vertex) -> c.int ---
GetGlyphShape :: proc(info: ^fontinfo, glyph_index: c.int, vertices: ^[^]vertex) -> c.int ---
// frees the data allocated above
FreeShape :: proc(info: ^fontinfo, vertices: [^]vertex) ---
// fills svg with the character's SVG data.
// returns data size or 0 if SVG not found.
FindSVGDoc :: proc(info: ^fontinfo, gl: b32) -> [^]byte ---
GetCodepointSVG :: proc(info: ^fontinfo, unicode_codepoint: rune, svg: ^cstring) -> c.int ---
GetGlyphSVG :: proc(info: ^fontinfo, gl: b32, svg: ^cstring) -> c.int ---
}
//////////////////////////////////////////////////////////////////////////////
//
// BITMAP RENDERING
//
_bitmap :: struct {
w, h, stride: c.int,
pixels: [^]byte,
}
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// frees the bitmap allocated below
FreeBitmap :: proc(bitmap: [^]byte, userdata: rawptr) ---
// allocates a large-enough single-channel 8bpp bitmap and renders the
// specified character/glyph at the specified scale into it, with
// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
// *width & *height are filled out with the width & height of the bitmap,
// which is stored left-to-right, top-to-bottom.
//
// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
GetCodepointBitmap :: proc(info: ^fontinfo, scale_x, scale_y: f32, codepoint: rune, width, height, xoff, yoff: ^c.int) -> [^]byte ---
// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
// shift for the character
GetCodepointBitmapSubpixel :: proc(info: ^fontinfo, scale_x, scale_y, shift_x, shift_y: f32, codepoint: rune, width, height, xoff, yoff: ^c.int) -> [^]byte ---
// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
// width and height and positioning info for it first.
MakeCodepointBitmap :: proc(info: ^fontinfo, output: [^]byte, out_w, out_h, out_stride: c.int, scale_x, scale_y: f32, codepoint: rune) ---
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
// shift for the character
MakeCodepointBitmapSubpixel :: proc(info: ^fontinfo, output: [^]byte, out_w, out_h, out_stride: c.int, scale_x, scale_y, shift_x, shift_y: f32, codepoint: rune) ---
// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
// is performed (see stbtt_PackSetOversampling)
MakeCodepointBitmapSubpixelPrefilter :: proc(info: ^fontinfo, output: [^]byte, out_w, out_h, out_stride: c.int, scale_x, scale_y, shift_x, shift_y: f32, oversample_x, oversample_y: b32, sub_x, sub_y: ^f32, codepoint: rune) ---
// get the bbox of the bitmap centered around the glyph origin; so the
// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
// the bitmap top left is (leftSideBearing*scale,iy0).
// (Note that the bitmap uses y-increases-down, but the shape uses
// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
GetCodepointBitmapBox :: proc(font: ^fontinfo, codepoint: rune, scale_x, scale_y: f32, ix0, iy0, ix1, iy1: ^c.int) ---
// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
// shift for the character
GetCodepointBitmapBoxSubpixel :: proc(font: ^fontinfo, codepoint: rune, scale_x, scale_y, shift_x, shift_y: f32, ix0, iy0, ix1, iy1: ^c.int) ---
// the following functions are equivalent to the above functions, but operate
// on glyph indices instead of Unicode codepoints (for efficiency)
GetGlyphBitmap :: proc(info: ^fontinfo, scale_x, scale_y: f32, glyph: c.int, width, height, xoff, yoff: ^c.int) -> [^]byte ---
GetGlyphBitmapSubpixel :: proc(info: ^fontinfo, scale_x, scale_y, shift_x, shift_y: f32, glyph: c.int, width, height, xoff, yoff: ^c.int) -> [^]byte ---
MakeGlyphBitmap :: proc(info: ^fontinfo, output: [^]byte, out_w, out_h, out_stride: c.int, scale_x, scale_y: f32, glyph: c.int) ---
MakeGlyphBitmapSubpixel :: proc(info: ^fontinfo, output: [^]byte, out_w, out_h, out_stride: c.int, scale_x, scale_y, shift_x, shift_y: f32, glyph: c.int) ---
MakeGlyphBitmapSubpixelPrefilter :: proc(info: ^fontinfo, output: [^]byte, out_w, out_h, out_stride: c.int, scale_x, scale_y, shift_x, shift_y: f32, oversample_x, oversample_y: c.int, sub_x, sub_y: ^f32, glyph: c.int) ---
GetGlyphBitmapBox :: proc(font: ^fontinfo, glyph: c.int, scale_x, scale_y: f32, ix0, iy0, ix1, iy1: ^c.int) ---
GetGlyphBitmapBoxSubpixel :: proc(font: ^fontinfo, glyph: c.int, scale_x, scale_y, shift_x, shift_y: f32, ix0, iy0, ix1, iy1: ^c.int) ---
// rasterize a shape with quadratic beziers into a bitmap
Rasterize :: proc(result: ^_bitmap, // 1-channel bitmap to draw into
flatness_in_pixels: f32, // allowable error of curve in pixels
vertices: [^]vertex, // array of vertices defining shape
num_verts: c.int, // number of vertices in above array
scale_x, scale_y: f32, // scale applied to input vertices
shift_x, shift_y: f32, // translation applied to input vertices
x_off, y_off: c.int, // another translation applied to input
invert: b32, // if non-zero, vertically flip shape
userdata: rawptr, // context for to STBTT_MALLOC
) ---
}
//////////////////////////////////////////////////////////////////////////////
//
// Signed Distance Function (or Field) rendering
//
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// frees the SDF bitmap allocated below
FreeSDF :: proc(bitmap: [^]u8, userdata: rawptr) ---
// These functions compute a discretized SDF field for a single character, suitable for storing
// in a single-channel texture, sampling with bilinear filtering, and testing against
// larger than some threshold to produce scalable fonts.
// info -- the font
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
// glyph/codepoint -- the character to generate the SDF for
// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0),
// which allows effects like bit outlines
// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
// if positive, > onedge_value is inside; if negative, < onedge_value is inside
// width,height -- output height & width of the SDF bitmap (including padding)
// xoff,yoff -- output origin of the character
// return value -- a 2D array of bytes 0..255, width*height in size
//
// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
// optimal use of the limited 0..255 for your application, trading off precision
// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
//
// Example:
// scale = stbtt_ScaleForPixelHeight(22)
// padding = 5
// onedge_value = 180
// pixel_dist_scale = 180/5.0 = 36.0
//
// This will create an SDF bitmap in which the character is about 22 pixels
// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
// shape, sample the SDF at each pixel and fill the pixel if the SDF value
// is greater than or equal to 180/255. (You'll actually want to antialias,
// which is beyond the scope of this example.) Additionally, you can compute
// offset outlines (e.g. to stroke the character border inside & outside,
// or only outside). For example, to fill outside the character up to 3 SDF
// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
// choice of variables maps a range from 5 pixels outside the shape to
// 2 pixels inside the shape to 0..255; this is intended primarily for apply
// outside effects only (the interior range is needed to allow proper
// antialiasing of the font at *smaller* sizes)
//
// The function computes the SDF analytically at each SDF pixel, not by e.g.
// building a higher-res bitmap and approximating it. In theory the quality
// should be as high as possible for an SDF of this size & representation, but
// unclear if this is true in practice (perhaps building a higher-res bitmap
// and computing from that can allow drop-out prevention).
//
// The algorithm has not been optimized at all, so expect it to be slow
// if computing lots of characters or very large sizes.
GetGlyphSDF :: proc(info: ^fontinfo, scale: f32, glyph, padding: c.int, onedge_value: u8, pixel_dist_scale: f32, width, height, xoff, yoff: ^c.int) -> ^u8 ---
GetCodepointSDF :: proc(info: ^fontinfo, scale: f32, codepoint, padding: c.int, onedge_value: u8, pixel_dist_scale: f32, width, height, xoff, yoff: ^c.int) -> ^u8 ---
}
//////////////////////////////////////////////////////////////////////////////
//
// Finding the right font...
//
// You should really just solve this offline, keep your own tables
// of what font is what, and don't try to get it out of the .ttf file.
// That's because getting it out of the .ttf file is really hard, because
// the names in the file can appear in many possible encodings, in many
// possible languages, and e.g. if you need a case-insensitive comparison,
// the details of that depend on the encoding & language in a complex way
// (actually underspecified in truetype, but also gigantic).
//
// But you can use the provided functions in two possible ways:
// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
// unicode-encoded names to try to find the font you want;
// you can run this before calling stbtt_InitFont()
//
// stbtt_GetFontNameString() lets you get any of the various strings
// from the file yourself and do your own comparisons on them.
// You have to have called stbtt_InitFont() first.
MACSTYLE_DONTCARE :: 0
MACSTYLE_BOLD :: 1
MACSTYLE_ITALIC :: 2
MACSTYLE_UNDERSCORE :: 4
MACSTYLE_NONE :: 8 // <= not same as 0, this makes us check the bitfield is 0
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
// returns the offset (not index) of the font that matches, or -1 if none
// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
// if you use any other flag, use a font name like "Arial"; this checks
// the 'macStyle' header field; i don't know if fonts set this consistently
FindMatchingFont :: proc(fontdata: [^]byte, name: cstring, flags: c.int) -> c.int ---
// returns 1/0 whether the first string interpreted as utf8 is identical to
// the second string interpreted as big-endian utf16... useful for strings from next func
CompareUTF8toUTF16_bigendian :: proc(s1: cstring, len1: c.int, s2: cstring, len2: c.int) -> c.int ---
// returns the string (which may be big-endian double byte, e.g. for unicode)
// and puts the length in bytes in *length.
//
// some of the values for the IDs are below; for more see the truetype spec:
// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
// http://www.microsoft.com/typography/otspec/name.htm
GetFontNameString :: proc(font: ^fontinfo, length: c.int, platformID: PLATFORM_ID, encodingID, languageID, nameID: c.int) -> cstring ---
}
PLATFORM_ID :: enum c.int { // platformID
PLATFORM_ID_UNICODE = 0,
PLATFORM_ID_MAC = 1,
PLATFORM_ID_ISO = 2,
PLATFORM_ID_MICROSOFT = 3,
}
// encodingID for PLATFORM_ID_UNICODE
UNICODE_EID_UNICODE_1_0 :: 0
UNICODE_EID_UNICODE_1_1 :: 1
UNICODE_EID_ISO_10646 :: 2
UNICODE_EID_UNICODE_2_0_BMP :: 3
UNICODE_EID_UNICODE_2_0_FULL :: 4
// encodingID for PLATFORM_ID_MICROSOFT
MS_EID_SYMBOL :: 0
MS_EID_UNICODE_BMP :: 1
MS_EID_SHIFTJIS :: 2
MS_EID_UNICODE_FULL :: 10
// encodingID for PLATFORM_ID_MAC; same as Script Manager codes
MAC_EID_ROMAN, MAC_EID_ARABIC :: 0, 4
MAC_EID_JAPANESE, MAC_EID_HEBREW :: 1, 5
MAC_EID_CHINESE_TRAD, MAC_EID_GREEK :: 2, 6
MAC_EID_KOREAN, MAC_EID_RUSSIAN :: 3, 7
// languageID for PLATFORM_ID_MICROSOFT; same as LCID...
// problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
MS_LANG_ENGLISH, MS_LANG_ITALIAN :: 0x0409, 0x0410
MS_LANG_CHINESE, MS_LANG_JAPANESE :: 0x0804, 0x0411
MS_LANG_DUTCH, MS_LANG_KOREAN :: 0x0413, 0x0412
MS_LANG_FRENCH, MS_LANG_RUSSIAN :: 0x040c, 0x0419
MS_LANG_GERMAN, MS_LANG_SPANISH :: 0x0407, 0x0409
MS_LANG_HEBREW, MS_LANG_SWEDISH :: 0x040d, 0x041D
// languageID for PLATFORM_ID_MAC
MAC_LANG_ENGLISH, MAC_LANG_JAPANESE :: 0, 11
MAC_LANG_ARABIC, MAC_LANG_KOREAN :: 12, 23
MAC_LANG_DUTCH, MAC_LANG_RUSSIAN :: 4, 32
MAC_LANG_FRENCH, MAC_LANG_SPANISH :: 1, 6
MAC_LANG_GERMAN, MAC_LANG_SWEDISH :: 2, 5
MAC_LANG_HEBREW, MAC_LANG_CHINESE_SIMPLIFIED :: 10, 33
MAC_LANG_ITALIAN, MAC_LANG_CHINESE_TRAD :: 3, 19