Add custom stb_truetype package/lib to thirdparty for vefontcache update
This commit is contained in:
parent
22cf5c653b
commit
a869ebab69
0
thirdparty/stb/lib/.gitkeep
vendored
Normal file
0
thirdparty/stb/lib/.gitkeep
vendored
Normal file
BIN
thirdparty/stb/lib/darwin/stb_truetype.a
vendored
Normal file
BIN
thirdparty/stb/lib/darwin/stb_truetype.a
vendored
Normal file
Binary file not shown.
BIN
thirdparty/stb/lib/stb_truetype.lib
vendored
Normal file
BIN
thirdparty/stb/lib/stb_truetype.lib
vendored
Normal file
Binary file not shown.
BIN
thirdparty/stb/lib/stb_truetype_wasm.o
vendored
Normal file
BIN
thirdparty/stb/lib/stb_truetype_wasm.o
vendored
Normal file
Binary file not shown.
60
thirdparty/stb/src/Makefile
vendored
Normal file
60
thirdparty/stb/src/Makefile
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
OS=$(shell uname)
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
all: darwin
|
||||
else
|
||||
all: unix
|
||||
endif
|
||||
|
||||
wasm:
|
||||
mkdir -p ../lib
|
||||
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image.c -o ../lib/stb_image_wasm.o -DSTBI_NO_STDIO
|
||||
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_write.c -o ../lib/stb_image_write_wasm.o -DSTBI_WRITE_NO_STDIO
|
||||
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_resize.c -o ../lib/stb_image_resize_wasm.o
|
||||
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_truetype.c -o ../lib/stb_truetype_wasm.o
|
||||
# $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_vorbis.c -o ../lib/stb_vorbis_wasm.o -DSTB_VORBIS_NO_STDIO
|
||||
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_rect_pack.c -o ../lib/stb_rect_pack_wasm.o
|
||||
$(CC) -c -Os --target=wasm32 stb_sprintf.c -o ../lib/stb_sprintf_wasm.o
|
||||
|
||||
unix:
|
||||
mkdir -p ../lib
|
||||
$(CC) -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c stb_sprintf.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_image_resize.a stb_image_resize.o
|
||||
$(AR) rcs ../lib/stb_truetype.a stb_truetype.o
|
||||
$(AR) rcs ../lib/stb_rect_pack.a stb_rect_pack.o
|
||||
$(AR) rcs ../lib/stb_vorbis.a stb_vorbis.o
|
||||
$(AR) rcs ../lib/stb_sprintf.a stb_sprintf.o
|
||||
#$(CC) -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o
|
||||
#$(CC) -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o
|
||||
#$(CC) -fPIC -shared -Wl,-soname=stb_image_resize.so -o ../lib/stb_image_resize.so stb_image_resize.o
|
||||
#$(CC) -fPIC -shared -Wl,-soname=stb_truetype.so -o ../lib/stb_truetype.so stb_image_truetype.o
|
||||
#$(CC) -fPIC -shared -Wl,-soname=stb_rect_pack.so -o ../lib/stb_rect_pack.so stb_rect_packl.o
|
||||
#$(CC) -fPIC -shared -Wl,-soname=stb_vorbis.so -o ../lib/stb_vorbis.so stb_vorbisl.o
|
||||
rm *.o
|
||||
|
||||
darwin:
|
||||
mkdir -p ../lib
|
||||
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image.c -o stb_image-x86_64.o -mmacosx-version-min=10.12
|
||||
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_image.c -o stb_image-arm64.o -mmacosx-version-min=10.12
|
||||
lipo -create stb_image-x86_64.o stb_image-arm64.o -output ../lib/darwin/stb_image.a
|
||||
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image_write.c -o stb_image_write-x86_64.o -mmacosx-version-min=10.12
|
||||
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_image_write.c -o stb_image_write-arm64.o -mmacosx-version-min=10.12
|
||||
lipo -create stb_image_write-x86_64.o stb_image_write-arm64.o -output ../lib/darwin/stb_image_write.a
|
||||
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image_resize.c -o stb_image_resize-x86_64.o -mmacosx-version-min=10.12
|
||||
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_image_resize.c -o stb_image_resize-arm64.o -mmacosx-version-min=10.12
|
||||
lipo -create stb_image_resize-x86_64.o stb_image_resize-arm64.o -output ../lib/darwin/stb_image_resize.a
|
||||
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_truetype.c -o stb_truetype-x86_64.o -mmacosx-version-min=10.12
|
||||
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_truetype.c -o stb_truetype-arm64.o -mmacosx-version-min=10.12
|
||||
lipo -create stb_truetype-x86_64.o stb_truetype-arm64.o -output ../lib/darwin/stb_truetype.a
|
||||
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_rect_pack.c -o stb_rect_pack-x86_64.o -mmacosx-version-min=10.12
|
||||
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_rect_pack.c -o stb_rect_pack-arm64.o -mmacosx-version-min=10.12
|
||||
lipo -create stb_rect_pack-x86_64.o stb_rect_pack-arm64.o -output ../lib/darwin/stb_rect_pack.a
|
||||
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-x86_64.o -mmacosx-version-min=10.12
|
||||
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-arm64.o -mmacosx-version-min=10.12
|
||||
lipo -create stb_vorbis-x86_64.o stb_vorbis-arm64.o -output ../lib/darwin/stb_vorbis.a
|
||||
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-x86_64.o -mmacosx-version-min=10.12
|
||||
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-arm64.o -mmacosx-version-min=10.12
|
||||
lipo -create stb_sprintf-x86_64.o stb_sprintf-arm64.o -output ../lib/darwin/stb_sprintf.a
|
||||
rm *.o
|
8
thirdparty/stb/src/build.bat
vendored
Normal file
8
thirdparty/stb/src/build.bat
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
@echo off
|
||||
|
||||
if not exist "..\lib" mkdir ..\lib
|
||||
|
||||
cl -nologo -MT -TC -O2 -c stb_image.c stb_truetype.c
|
||||
lib -nologo stb_truetype.obj -out:..\lib\stb_truetype.lib
|
||||
|
||||
del *.obj
|
10824
thirdparty/stb/src/gb/gb.h
vendored
Normal file
10824
thirdparty/stb/src/gb/gb.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
thirdparty/stb/src/stb_image.c
vendored
Normal file
2
thirdparty/stb/src/stb_image.c
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
7897
thirdparty/stb/src/stb_image.h
vendored
Normal file
7897
thirdparty/stb/src/stb_image.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
thirdparty/stb/src/stb_truetype.c
vendored
Normal file
2
thirdparty/stb/src/stb_truetype.c
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
5114
thirdparty/stb/src/stb_truetype.h
vendored
Normal file
5114
thirdparty/stb/src/stb_truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
660
thirdparty/stb/truetype/stb_truetype.odin
vendored
Normal file
660
thirdparty/stb/truetype/stb_truetype.odin
vendored
Normal file
@ -0,0 +1,660 @@
|
||||
package stb_truetype
|
||||
|
||||
import c "core:c"
|
||||
import stbrp "vendor:stb/rect_pack"
|
||||
|
||||
@(private)
|
||||
LIB :: (
|
||||
"../lib/stb_truetype.lib" when ODIN_OS == .Windows
|
||||
else "../lib/stb_truetype.a" when ODIN_OS == .Linux
|
||||
else "../lib/darwin/stb_truetype.a" when ODIN_OS == .Darwin
|
||||
else "../lib/stb_truetype_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
|
||||
else ""
|
||||
)
|
||||
|
||||
when LIB != "" {
|
||||
when !#exists(LIB) {
|
||||
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||
foreign import stbtt "../lib/stb_truetype_wasm.o"
|
||||
} else when LIB != "" {
|
||||
foreign import stbtt { LIB }
|
||||
} else {
|
||||
foreign import stbtt "system:stb_truetype"
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
////
|
||||
//// INTERFACE
|
||||
////
|
||||
////
|
||||
|
||||
#assert(size_of(c.int) == size_of(rune))
|
||||
#assert(size_of(c.int) == size_of(b32))
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CUSTOM: ODIN COMPATIBLE ALLOCATOR
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
gbAllocationType :: enum(i32) {
|
||||
Alloc,
|
||||
Free,
|
||||
FreeAll,
|
||||
Resize,
|
||||
}
|
||||
|
||||
gbAllocatorProc :: #type proc(allocator_data: rawptr, type: gbAllocationType,
|
||||
size: c.ssize_t, alignment: c.ssize_t,
|
||||
old_memory: rawptr, old_size: c.ssize_t,
|
||||
flags : c.ulonglong
|
||||
) -> rawptr
|
||||
|
||||
gbAllocator :: struct {
|
||||
procedure: gbAllocatorProc,
|
||||
data: rawptr,
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="stbtt_")
|
||||
foreign stbtt {
|
||||
SetAllocator :: proc(allocator : gbAllocator) ---
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// END CUSTOM: ODIN COMPATIBLE ALLOCATOR
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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,
|
||||
skip_missing: b32,
|
||||
h_oversample, v_oversample: u32,
|
||||
pixels: [^]byte,
|
||||
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, #by_ptr 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, #by_ptr 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, gpos, svg: 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: [^]byte, 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) -> c.int ---
|
||||
|
||||
// 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(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr info: fontinfo, typoAscent, typoDescent, typoLineGap: ^c.int) -> b32 ---
|
||||
|
||||
// the bounding box around all possible characters
|
||||
GetFontBoundingBox :: proc(#by_ptr 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(#by_ptr info: fontinfo, codepoint: rune, advanceWidth, leftSideBearing: ^c.int) ---
|
||||
|
||||
// an additional amount to add to the 'advance' value between ch1 and ch2
|
||||
GetCodepointKernAdvance :: proc(#by_ptr info: fontinfo, ch1, ch2: rune) -> (advance: c.int) ---
|
||||
|
||||
// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
|
||||
GetCodepointBox :: proc(#by_ptr 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(#by_ptr info: fontinfo, glyph_index: c.int, advanceWidth, leftSideBearing: ^c.int) ---
|
||||
GetGlyphKernAdvance :: proc(#by_ptr info: fontinfo, glyph1, glyph2: c.int) -> c.int ---
|
||||
GetGlyphBox :: proc(#by_ptr 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(#by_ptr info: fontinfo) -> c.int ---
|
||||
GetKerningTable :: proc(#by_ptr 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(#by_ptr 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(#by_ptr info: fontinfo, unicode_codepoint: rune, vertices: ^[^]vertex) -> c.int ---
|
||||
GetGlyphShape :: proc(#by_ptr info: fontinfo, glyph_index: c.int, vertices: ^[^]vertex) -> c.int ---
|
||||
|
||||
// frees the data allocated above
|
||||
FreeShape :: proc(#by_ptr info: fontinfo, vertices: [^]vertex) ---
|
||||
|
||||
// fills svg with the character's SVG data.
|
||||
// returns data size or 0 if SVG not found.
|
||||
FindSVGDoc :: proc(#by_ptr info: fontinfo, gl: b32) -> [^]byte ---
|
||||
GetCodepointSVG :: proc(#by_ptr info: fontinfo, unicode_codepoint: rune, svg: ^cstring) -> c.int ---
|
||||
GetGlyphSVG :: proc(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr 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(#by_ptr info: fontinfo, scale_x, scale_y: f32, glyph: c.int, width, height, xoff, yoff: ^c.int) -> [^]byte ---
|
||||
GetGlyphBitmapSubpixel :: proc(#by_ptr info: fontinfo, scale_x, scale_y, shift_x, shift_y: f32, glyph: c.int, width, height, xoff, yoff: ^c.int) -> [^]byte ---
|
||||
MakeGlyphBitmap :: proc(#by_ptr info: fontinfo, output: [^]byte, out_w, out_h, out_stride: c.int, scale_x, scale_y: f32, glyph: c.int) ---
|
||||
MakeGlyphBitmapSubpixel :: proc(#by_ptr 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(#by_ptr 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(#by_ptr font: fontinfo, glyph: c.int, scale_x, scale_y: f32, ix0, iy0, ix1, iy1: ^c.int) ---
|
||||
GetGlyphBitmapBoxSubpixel :: proc(#by_ptr 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: [^]byte, 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(#by_ptr info: fontinfo, scale: f32, glyph, padding: c.int, onedge_value: u8, pixel_dist_scale: f32, width, height, xoff, yoff: ^c.int) -> [^]byte ---
|
||||
GetCodepointSDF :: proc(#by_ptr info: fontinfo, scale: f32, codepoint, padding: c.int, onedge_value: u8, pixel_dist_scale: f32, width, height, xoff, yoff: ^c.int) -> [^]byte ---
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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(#by_ptr 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
|
||||
|
||||
// private structure
|
||||
_buf :: struct {
|
||||
data: [^]byte,
|
||||
cursor: c.int,
|
||||
size: c.int,
|
||||
}
|
4
thirdparty/stb/truetype/stb_truetype_wasm.odin
vendored
Normal file
4
thirdparty/stb/truetype/stb_truetype_wasm.odin
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
#+build wasm32, wasm64p32
|
||||
package stb_truetype
|
||||
|
||||
@(require) import _ "vendor:libc"
|
Loading…
x
Reference in New Issue
Block a user