251 lines
5.5 KiB
Zig
251 lines
5.5 KiB
Zig
const std = @import("std");
|
|
|
|
const Font = @import("./font.zig");
|
|
const Align = Font.Align;
|
|
|
|
const Context = @This();
|
|
|
|
const c = @cImport({
|
|
@cInclude("fontstash.h");
|
|
|
|
@cInclude("sokol/sokol_gfx.h");
|
|
@cInclude("sokol/sokol_gl.h");
|
|
@cInclude("sokol_fontstash.h");
|
|
});
|
|
|
|
pub const FONScontext = c.FONScontext;
|
|
|
|
pub const Size = struct {
|
|
width: u32,
|
|
height: u32,
|
|
};
|
|
|
|
pub const TextBounds = struct {
|
|
advance: f32,
|
|
min_x: f32,
|
|
max_x: f32,
|
|
min_y: f32,
|
|
max_y: f32,
|
|
};
|
|
|
|
pub const LineBounds = struct {
|
|
min_y: f32,
|
|
max_y: f32,
|
|
};
|
|
|
|
pub const VertMetrics = struct {
|
|
ascender: f32,
|
|
descender: f32,
|
|
lineh: f32
|
|
};
|
|
|
|
pub const Quad = struct {
|
|
x0: f32,
|
|
y0: f32,
|
|
s0: f32,
|
|
t0: f32,
|
|
|
|
x1: f32,
|
|
y1: f32,
|
|
s1: f32,
|
|
t1: f32,
|
|
};
|
|
|
|
pub const TextIterator = struct {
|
|
context: Context,
|
|
iter: c.FONStextIter,
|
|
|
|
pub fn init(ctx: Context, x: f32, y: f32, text: []const u8) TextIterator {
|
|
var self = TextIterator{
|
|
.context = ctx,
|
|
.iter = undefined
|
|
};
|
|
|
|
const success = c.fonsTextIterInit(
|
|
self.context.ctx,
|
|
&self.iter,
|
|
x,
|
|
y,
|
|
text.ptr,
|
|
text.ptr + text.len
|
|
);
|
|
if (success != 1) {
|
|
return error.fonsTextIterInit;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
pub fn next(self: TextIterator) ?Quad {
|
|
var quad: c.FONSquad = undefined;
|
|
const success = c.fonsTextIterNext(self.context, &self.iter, &quad);
|
|
if (success != 1) {
|
|
return null;
|
|
}
|
|
|
|
return Quad{
|
|
.x0 = quad.x0,
|
|
.y0 = quad.y0,
|
|
.s0 = quad.s0,
|
|
.t0 = quad.t0,
|
|
|
|
.x1 = quad.x0,
|
|
.y1 = quad.y0,
|
|
.s1 = quad.s0,
|
|
.t1 = quad.t0,
|
|
};
|
|
}
|
|
};
|
|
|
|
ctx: *FONScontext,
|
|
|
|
pub fn init(desc: c.sfons_desc_t) !Context {
|
|
const ctx = c.sfons_create(&desc);
|
|
if (ctx == null) {
|
|
return error.sfons_create;
|
|
}
|
|
|
|
return Context{
|
|
.ctx = ctx.?
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: Context) void {
|
|
c.sfons_destroy(self.ctx);
|
|
}
|
|
|
|
pub fn flush(self: Context) void {
|
|
c.sfons_flush(self.ctx);
|
|
}
|
|
|
|
pub fn addFont(self: Context, name: [*c]const u8, data: []const u8) !Font.Id {
|
|
const font_id = c.fonsAddFontMem(
|
|
self.ctx,
|
|
name,
|
|
@constCast(data.ptr),
|
|
@intCast(data.len),
|
|
0
|
|
);
|
|
if (font_id == c.FONS_INVALID) {
|
|
return error.fonsAddFontMem;
|
|
}
|
|
return @enumFromInt(font_id);
|
|
}
|
|
|
|
pub fn addFallbackFont(self: Context, base: Font.Id, fallback: Font.Id) void {
|
|
const success = c.fonsAddFallbackFont(self.ctx, @intFromEnum(base), @intFromEnum(fallback));
|
|
if (success != 1) {
|
|
return error.fonsAddFallbackFont;
|
|
}
|
|
}
|
|
|
|
pub fn getFontByName(self: Context, name: [*c]const u8) ?Font.Id {
|
|
const font_id = c.fonsGetFontByName(self.ctx, name);
|
|
if (font_id == c.FONS_INVALID) {
|
|
return null;
|
|
}
|
|
return @enumFromInt(font_id);
|
|
}
|
|
|
|
// TODO: fonsSetErrorCallback
|
|
|
|
pub fn getAtlasSize(self: Context) Size {
|
|
var result: Size = .{
|
|
.width = 0,
|
|
.height = 0
|
|
};
|
|
c.fonsGetAtlasSize(self.ctx, &result.width, &result.height);
|
|
return result;
|
|
}
|
|
|
|
pub fn expandAtlas(self: Context, width: u32, height: u32) !void {
|
|
const success = c.fonsExpandAtlas(self.ctx, @bitCast(width), @bitCast(height));
|
|
if (success != 1) {
|
|
return error.fonsExpandAtlas;
|
|
}
|
|
}
|
|
|
|
pub fn resetAtlas(self: Context) !void {
|
|
const success = c.fonsResetAtlas(self.ctx);
|
|
if (success != 1) {
|
|
return error.fonsResetAtlas;
|
|
}
|
|
}
|
|
|
|
pub fn pushState(self: Context) void {
|
|
c.fonsPushState(self.ctx);
|
|
}
|
|
|
|
pub fn popState(self: Context) void {
|
|
c.fonsPopState(self.ctx);
|
|
}
|
|
|
|
pub fn clearState(self: Context) void {
|
|
c.fonsClearState(self.ctx);
|
|
}
|
|
|
|
pub fn setSize(self: Context, size: f32) void {
|
|
c.fonsSetSize(self.ctx, size);
|
|
}
|
|
|
|
pub fn setColor(self: Context, color: u32) void {
|
|
c.fonsSetColor(self.ctx, color);
|
|
}
|
|
|
|
pub fn setSpacing(self: Context, spacing: f32) void {
|
|
c.fonsSetSpacing(self.ctx, spacing);
|
|
}
|
|
|
|
pub fn setBlur(self: Context, blur: f32) void {
|
|
c.fonsSetSpacing(self.ctx, blur);
|
|
}
|
|
|
|
pub fn setAlign(self: Context, alignment: Align) void {
|
|
c.fonsSetAlign(self.ctx, @intFromEnum(alignment.x) | @intFromEnum(alignment.y));
|
|
}
|
|
|
|
pub fn setFont(self: Context, id: Font.Id) void {
|
|
c.fonsSetFont(self.ctx, @intFromEnum(id));
|
|
}
|
|
|
|
pub fn drawText(self: Context, x: f32, y: f32, text: []const u8) void {
|
|
const advance = c.fonsDrawText(self.ctx, x, y, text.ptr, text.ptr + text.len);
|
|
_ = advance;
|
|
}
|
|
|
|
pub fn textBounds(self: Context, x: f32, y: f32, text: []const u8) TextBounds {
|
|
var bounds: f32[4] = undefined;
|
|
const advance = c.fonsTextBounds(self.ctx, x, y, text.ptr, text.ptr + text.len, &bounds);
|
|
|
|
return TextBounds{
|
|
.advance = advance,
|
|
.min_x = bounds[0],
|
|
.max_x = bounds[1],
|
|
.min_y = bounds[2],
|
|
.max_y = bounds[3]
|
|
};
|
|
}
|
|
|
|
pub fn lineBounds(self: Context, y: f32) LineBounds {
|
|
var result: LineBounds = .{
|
|
.max_y = 0,
|
|
.min_y = 0
|
|
};
|
|
c.fonsLineBounds(self.ctx, y, &result.min_y, &result.max_y);
|
|
return result;
|
|
}
|
|
|
|
pub fn vertMetrics(self: Context) void {
|
|
var result: VertMetrics = .{
|
|
.ascender = 0,
|
|
.descender = 0,
|
|
.lineh = 0
|
|
};
|
|
c.fonsVertMetrics(self.ctx, &result.ascender, &result.descender, &result.lineh);
|
|
return result;
|
|
}
|
|
|
|
pub fn drawDebug(self: Context, x: f32, y: f32) void {
|
|
c.fonsDrawDebug(self.ctx, x, y);
|
|
}
|