Add some examples to the docs; Improve numerous procedures

This commit is contained in:
gingerBill
2025-12-08 12:10:50 +00:00
parent 6002a29c51
commit c284fcb3a3
2 changed files with 125 additions and 8 deletions

59
vendor/kb_text_shape/doc.odin vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
Bindings for [[ Jimmy Lefevre's Text Shape ; https://github.com/JimmyLefevre/kb ]] Unicode text segmentation and OpenType shaping.
Example:
// Basic
OdinAllocator := context.allocator
FontData, _ := os.read_entire_file("myfonts.ttf", OdinAllocator)
Context := kbts.CreateShapeContext(kbts.AllocatorFromOdinAllocator(&OdinAllocator))
kbts.ShapePushFontFromMemory(Context, FontData, 0)
kbts.ShapeBegin(Context, .DONT_KNOW, .DONT_KNOW)
kbts.ShapeUtf8(Context, "Let's shape something!", .CODEPOINT_INDEX)
kbts.ShapeEnd(Context)
CursorX, CursorY: c.int = 0, 0
for Run in kbts.ShapeRun(Context) {
Run := Run
for Glyph in kbts.GlyphIteratorNext(&Run.Glyphs) {
GlyphX := CursorX + Glyph.OffsetX
GlyphY := CursorY + Glyph.OffsetY
_ = GlyphX
_ = GlyphY
// DisplayGlyph(Glyph.Id, GlyphX, GlyphY)
CursorX += Glyph.AdvanceX
CursorY += Glyph.AdvanceY
}
}
Example:
// Font collections
OdinAllocator := context.allocator
FontData, _ := os.read_entire_file("myfonts.ttf", OdinAllocator)
Font := kbts.FontFromMemory(FontData, 0, kbts.AllocatorFromOdinAllocator(&OdinAllocator))
_ = kbts.ShapePushFont(Context, &Font)
FontCount := kbts.FontCount(FontData)
for FontIndex in 1..<FontCount {
kbts.ShapePushFontFromMemory(Context, FontData, FontIndex)
}
Example:
kbts.ShapeBegin(Context, .DONT_KNOW, .DONT_KNOW)
kbts.ShapePushFeature(Context, .kern, 0)
kbts.ShapeUtf8(Context, "Without kerning", .CODEPOINT_INDEX)
_ = kbts.ShapePopFeature(Context, .kern)
kbts.ShapeUtf8(Context, "With kerning", .CODEPOINT_INDEX)
kbts.ShapeEnd(Context)
*/
package vendor_kb_text_shape

View File

@@ -1,4 +1,3 @@
// Bindings for [[ Jimmy Lefevre's Text Shape ; https://github.com/JimmyLefevre/kb ]] Unicode text segmentation and OpenType shaping.
package vendor_kb_text_shape
when ODIN_OS == .Windows {
@@ -11,6 +10,7 @@ when ODIN_OS == .Windows {
}
}
import "base:runtime"
import "core:c"
//
@@ -21,16 +21,14 @@ import "core:c"
foreign lib {
SizeOfShapeContext :: proc() -> c.int ---
PlaceShapeContext :: proc(Allocator: allocator_function, AllocatorData: rawptr, Memory: rawptr) -> ^shape_context ---
PlaceShapeContextFixedMemory :: proc(Memory: rawptr, Size: c.int) -> ^shape_context ---
CreateShapeContext :: proc(Allocator: allocator_function, AllocatorData: rawptr) -> ^shape_context ---
DestroyShapeContext :: proc(Context: ^shape_context) ---
ShapePushFontFromMemory :: proc(Context: ^shape_context, Memory: rawptr, Size: c.int, FontIndex: c.int) -> ^font ---
ShapePushFont :: proc(Context: ^shape_context, Font: ^font) -> ^font ---
ShapePopFont :: proc(Context: ^shape_context) -> ^font ---
ShapeBegin :: proc(Context: ^shape_context, ParagraphDirection: direction, Language: language) ---
ShapeEnd :: proc(Context: ^shape_context) ---
ShapePushFeature :: proc(Context: ^shape_context, FeatureTag: u32, Value: c.int) ---
ShapePopFeature :: proc(Context: ^shape_context, FeatureTag: u32) -> b32 ---
ShapePushFeature :: proc(Context: ^shape_context, FeatureTag: feature_tag, Value: c.int) ---
ShapePopFeature :: proc(Context: ^shape_context, FeatureTag: feature_tag) -> b32 ---
ShapeCodepoint :: proc(Context: ^shape_context, Codepoint: rune) ---
ShapeCodepointWithUserId :: proc(Context: ^shape_context, Codepoint: rune, UserId: c.int) ---
ShapeError :: proc(Context: ^shape_context) -> shape_error ---
@@ -40,6 +38,23 @@ foreign lib {
ShapeManualBreak :: proc(Context: ^shape_context) ---
}
@(require_results)
PlaceShapeContextFixedMemory :: proc "c" (Memory: []byte) -> ^shape_context {
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
PlaceShapeContextFixedMemory :: proc(Memory: rawptr, Size: c.int) -> ^shape_context ---
}
return PlaceShapeContextFixedMemory(raw_data(Memory), c.int(len(Memory)))
}
ShapePushFontFromMemory :: proc "c" (Context: ^shape_context, Memory: []byte, FontIndex: c.int) -> ^font {
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
ShapePushFontFromMemory :: proc(Context: ^shape_context, Memory: rawptr, Size: c.int, FontIndex: c.int) -> ^font ---
}
return ShapePushFontFromMemory(Context, raw_data(Memory), c.int(len(Memory)), FontIndex)
}
@(require_results)
ShapeRun :: proc "contextless" (Context: ^shape_context) -> (Run: run, ok: b32) {
@(default_calling_convention="c", link_prefix="kbts_", require_results)
@@ -105,8 +120,6 @@ ShapeCodepointIteratorNext :: proc "contextless" (It: ^shape_codepoint_iterator)
//
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
FontCount :: proc(FileData: rawptr, FileSize: c.int) -> b32 ---
FontFromMemory :: proc(FileData: rawptr, FileSize: c.int, FontIndex: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> font ---
FreeFont :: proc(Font: ^font) ---
FontIsValid :: proc(Font: ^font) -> b32 ---
LoadFont :: proc(Font: ^font, State: ^load_font_state, FontData: rawptr, FontDataSize: c.int, FontIndex: c.int, ScratchSize_: ^c.int, OutputSize_: ^c.int) -> load_font_error ---
@@ -135,6 +148,24 @@ foreign lib {
DestroyGlyphConfig :: proc(Config: ^glyph_config) ---
}
@(require_results)
FontCount :: proc "c" (FileData: []byte) -> c.int {
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
FontCount :: proc(FileData: rawptr, FileSize: c.int) -> c.int ---
}
return FontCount(raw_data(FileData), c.int(len(FileData)))
}
@(require_results)
FontFromMemory :: proc "c" (FileData: []byte, FontIndex: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> font {
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
FontFromMemory :: proc(FileData: rawptr, FileSize: c.int, FontIndex: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> font ---
}
return FontFromMemory(raw_data(FileData), c.int(len(FileData)), FontIndex, Allocator, AllocatorData)
}
@(require_results)
ShapeDirect :: proc "contextless" (Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Allocator: allocator_function, AllocatorData: rawptr) -> (Output: glyph_iterator, err: shape_error) {
@@ -321,4 +352,31 @@ GuessTextPropertiesUtf8 :: proc "contextless" (Utf8: string) -> (Direction: dire
}
GuessTextPropertiesUtf8(cstring(raw_data(Utf8)), c.int(len(Utf8)), &Direction, &Script)
return
}
}
@(require_results)
AllocatorFromOdinAllocator :: proc "contextless" (allocator: ^runtime.Allocator) -> (Allocator: allocator_function, AllocatorData: rawptr) {
allocator_function :: proc "c" (Data: rawptr, Op: ^allocator_op) {
if Data == nil {
return
}
context = runtime.default_context()
context.allocator = (^runtime.Allocator)(Data)^
switch Op.Kind {
case .NONE:
return
case .ALLOCATE:
data, _ := runtime.mem_alloc(int(Op.Allocate.Size), runtime.DEFAULT_ALIGNMENT)
Op.Allocate.Pointer = raw_data(data)
Op.Allocate.Size = u32(len(data))
case .FREE:
_ = runtime.mem_free(Op.Free.Pointer)
}
}
return allocator_function, rawptr(allocator)
}