add fontstash
This commit is contained in:
parent
44968f35f2
commit
12cf7201ac
@ -16,3 +16,10 @@ Cross-compile for Windows from Linux:
|
||||
```sh
|
||||
zig build -Dtarget=x86_64-windows
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
* Use [Skribidi](https://github.com/memononen/Skribidi) instead of fontstash for text rendering
|
||||
* Gamepad support.
|
||||
* WASM Support. Currently a build config isn't provided for this target.
|
||||
* Update build config for other platforms to reduce binary size. All of the video and audio drivers aren't needed, only gamepads
|
||||
|
||||
57
build.zig
57
build.zig
@ -3,7 +3,7 @@ const cimgui = @import("cimgui");
|
||||
const sokol = @import("sokol");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
@ -11,7 +11,9 @@ pub fn build(b: *std.Build) void {
|
||||
var has_tracy = b.option(bool, "tracy", "Tracy integration") orelse (optimize == .Debug);
|
||||
const has_console = b.option(bool, "console", "Show console (Window only)") orelse (optimize == .Debug);
|
||||
|
||||
if (target.result.cpu.arch.isWasm()) {
|
||||
const isWasm = target.result.cpu.arch.isWasm();
|
||||
|
||||
if (isWasm) {
|
||||
has_tracy = false;
|
||||
}
|
||||
|
||||
@ -19,6 +21,7 @@ pub fn build(b: *std.Build) void {
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true
|
||||
});
|
||||
|
||||
const cimgui_conf = cimgui.getConfig(false);
|
||||
@ -27,6 +30,7 @@ pub fn build(b: *std.Build) void {
|
||||
.optimize = optimize,
|
||||
.with_sokol_imgui = has_imgui,
|
||||
});
|
||||
mod_main.linkLibrary(dep_sokol.artifact("sokol_clib"));
|
||||
mod_main.addImport("sokol", dep_sokol.module("sokol"));
|
||||
|
||||
if (has_imgui) {
|
||||
@ -56,6 +60,41 @@ pub fn build(b: *std.Build) void {
|
||||
const dep_stb_image = b.dependency("stb_image", .{});
|
||||
mod_main.addImport("stb_image", dep_stb_image.module("stb_image"));
|
||||
|
||||
const dep_fontstash_c = b.dependency("fontstash_c", .{});
|
||||
mod_main.addIncludePath(dep_fontstash_c.path("src"));
|
||||
|
||||
const dep_sokol_c = b.dependency("sokol_c", .{});
|
||||
{
|
||||
var cflags_buffer: [64][]const u8 = undefined;
|
||||
var cflags = std.ArrayListUnmanaged([]const u8).initBuffer(&cflags_buffer);
|
||||
switch (sokol.resolveSokolBackend(.auto, target.result)) {
|
||||
.d3d11 => try cflags.appendBounded("-DSOKOL_D3D11"),
|
||||
.metal => try cflags.appendBounded("-DSOKOL_METAL"),
|
||||
.gl => try cflags.appendBounded("-DSOKOL_GLCORE"),
|
||||
.gles3 => try cflags.appendBounded("-DSOKOL_GLES3"),
|
||||
.wgpu => try cflags.appendBounded("-DSOKOL_WGPU"),
|
||||
else => @panic("unknown sokol backend"),
|
||||
}
|
||||
|
||||
mod_main.addIncludePath(dep_sokol_c.path("util"));
|
||||
mod_main.addCSourceFile(.{
|
||||
.file = b.path("src/engine/fontstash/sokol_fontstash_impl.c"),
|
||||
.flags = cflags.items
|
||||
});
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// const sdl = b.dependency("sdl", .{
|
||||
// .optimize = optimize,
|
||||
// .target = target,
|
||||
// .linkage = .static,
|
||||
// .default_target_config = !isWasm
|
||||
// });
|
||||
// mod_main.linkLibrary(sdl.artifact("SDL3"));
|
||||
// if (isWasm) {
|
||||
// // TODO: Define buid config for wasm
|
||||
// }
|
||||
|
||||
var options = b.addOptions();
|
||||
options.addOption(bool, "has_imgui", has_imgui);
|
||||
options.addOption(bool, "has_tracy", has_tracy);
|
||||
@ -96,7 +135,6 @@ fn buildNative(b: *std.Build, name: []const u8, mod: *std.Build.Module, has_cons
|
||||
const png_to_icon_step = b.addRunArtifact(png_to_icon_tool);
|
||||
png_to_icon_step.addFileArg(b.path("src/assets/icon.png"));
|
||||
const icon_file = png_to_icon_step.addOutputFileArg("icon.ico");
|
||||
// const icon_file = b.path("src/assets/icon.ico"); // png_to_icon_step.addOutputFileArg("icon.ico");
|
||||
|
||||
const add_icon_step = AddExecutableIcon.init(exe, icon_file);
|
||||
exe.step.dependOn(&add_icon_step.step);
|
||||
@ -139,13 +177,14 @@ fn patchWasmIncludeDirs(
|
||||
path: std.Build.LazyPath,
|
||||
depend_step: *std.Build.Step
|
||||
) void {
|
||||
if (module.link_libc != null and module.link_libc.?) {
|
||||
// need to inject the Emscripten system header include path into
|
||||
// the cimgui C library otherwise the C/C++ code won't find
|
||||
// C stdlib headers
|
||||
module.addSystemIncludePath(path);
|
||||
}
|
||||
|
||||
for (module.import_table.values()) |imported_module| {
|
||||
if (imported_module.link_libc != null and imported_module.link_libc.?) {
|
||||
// need to inject the Emscripten system header include path into
|
||||
// the cimgui C library otherwise the C/C++ code won't find
|
||||
// C stdlib headers
|
||||
imported_module.addSystemIncludePath(path);
|
||||
}
|
||||
patchWasmIncludeDirs(imported_module, path, depend_step);
|
||||
}
|
||||
|
||||
|
||||
@ -8,21 +8,33 @@
|
||||
.url = "git+https://github.com/floooh/sokol-zig.git#aaf291ca2d3d1cedc05d65f5a1cacae0f53d934a",
|
||||
.hash = "sokol-0.1.0-pb1HK4iDNgCom5dkY66eUBm_bYBHEl8KWFDAiqwWgpEy",
|
||||
},
|
||||
.sokol_c = .{
|
||||
.url = "git+https://github.com/floooh/sokol.git#c66a1f04e6495d635c5e913335ab2308281e0492",
|
||||
.hash = "N-V-__8AAC3eYABB1DVLb4dkcEzq_xVeEZZugVfQ6DoNQBDN",
|
||||
},
|
||||
.fontstash_c = .{
|
||||
.url = "git+https://github.com/memononen/fontstash.git#b5ddc9741061343740d85d636d782ed3e07cf7be",
|
||||
.hash = "N-V-__8AAA9xHgAxdLYPmlNTy6qzv9IYqiIePEHQUOPWYQ_6",
|
||||
},
|
||||
.cimgui = .{
|
||||
.url = "git+https://github.com/floooh/dcimgui.git#33c99ef426b68030412b5a4b11487a23da9d4f13",
|
||||
.hash = "cimgui-0.1.0-44ClkQRJlABdFMKRqIG8KDD6jy1eQbgPO335NziPYjmL",
|
||||
.lazy = true
|
||||
.lazy = true,
|
||||
},
|
||||
.tracy = .{
|
||||
.url = "git+https://github.com/sagehane/zig-tracy.git#80933723efe9bf840fe749b0bfc0d610f1db1669",
|
||||
.hash = "zig_tracy-0.0.5-aOIqsX1tAACKaRRB-sraMLuNiMASXi_y-4FtRuw4cTpx",
|
||||
},
|
||||
.tiled = .{
|
||||
.path = "./libs/tiled"
|
||||
.path = "./libs/tiled",
|
||||
},
|
||||
.stb_image = .{
|
||||
.path = "./libs/stb_image"
|
||||
}
|
||||
.path = "./libs/stb_image",
|
||||
},
|
||||
// .sdl = .{
|
||||
// .url = "git+https://github.com/allyourcodebase/SDL3.git#f85824b0db782b7d01c60aaad8bcb537892394e8",
|
||||
// .hash = "sdl-0.0.0-i4QD0UuFqADRQysNyJ1OvCOZnq-clcVhq3BfPcBOf9zr",
|
||||
// },
|
||||
},
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
|
||||
@ -1,8 +1,27 @@
|
||||
const std = @import("std");
|
||||
const Gfx = @import("./engine/graphics.zig");
|
||||
|
||||
const Assets = @This();
|
||||
|
||||
const FontName = enum {
|
||||
regular,
|
||||
bold,
|
||||
italic,
|
||||
|
||||
const EnumArray = std.EnumArray(FontName, Gfx.Font.Id);
|
||||
};
|
||||
|
||||
font_id: FontName.EnumArray,
|
||||
|
||||
pub fn init() !Assets {
|
||||
const font_id_array: FontName.EnumArray = .init(.{
|
||||
.regular = try Gfx.addFont("regular", @embedFile("assets/roboto-font/Roboto-Regular.ttf")),
|
||||
.bold = try Gfx.addFont("bold", @embedFile("assets/roboto-font/Roboto-Bold.ttf")),
|
||||
.italic = try Gfx.addFont("italic", @embedFile("assets/roboto-font/Roboto-Italic.ttf")),
|
||||
});
|
||||
|
||||
return Assets{
|
||||
.font_id = font_id_array
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
250
src/engine/fontstash/context.zig
Normal file
250
src/engine/fontstash/context.zig
Normal file
@ -0,0 +1,250 @@
|
||||
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);
|
||||
}
|
||||
33
src/engine/fontstash/font.zig
Normal file
33
src/engine/fontstash/font.zig
Normal file
@ -0,0 +1,33 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @cImport({
|
||||
@cInclude("fontstash.h");
|
||||
});
|
||||
|
||||
const Font = @This();
|
||||
|
||||
pub const Id = enum(c_int) {
|
||||
_,
|
||||
|
||||
pub const invalid: Id = @enumFromInt(c.FONS_INVALID);
|
||||
};
|
||||
|
||||
pub const AlignX = enum(c_int) {
|
||||
left = c.FONS_ALIGN_LEFT,
|
||||
right = c.FONS_ALIGN_RIGHT,
|
||||
center = c.FONS_ALIGN_CENTER,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const AlignY = enum(c_int) {
|
||||
top = c.FONS_ALIGN_TOP,
|
||||
middle = c.FONS_ALIGN_MIDDLE,
|
||||
bottom = c.FONS_ALIGN_BOTTOM,
|
||||
baseline = c.FONS_ALIGN_BASELINE,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const Align = struct {
|
||||
x: AlignX,
|
||||
y: AlignY,
|
||||
};
|
||||
3
src/engine/fontstash/root.zig
Normal file
3
src/engine/fontstash/root.zig
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
pub const Font = @import("./font.zig");
|
||||
pub const Context = @import("./context.zig");
|
||||
12
src/engine/fontstash/sokol_fontstash_impl.c
Normal file
12
src/engine/fontstash/sokol_fontstash_impl.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#define FONTSTASH_IMPLEMENTATION
|
||||
#include "fontstash.h"
|
||||
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include "sokol/sokol_gl.h"
|
||||
#define SOKOL_FONTSTASH_IMPL
|
||||
#include "sokol_fontstash.h"
|
||||
@ -18,6 +18,8 @@ const assert = std.debug.assert;
|
||||
|
||||
const imgui = @import("imgui.zig");
|
||||
const tracy = @import("tracy");
|
||||
const fontstash = @import("./fontstash/root.zig");
|
||||
pub const Font = fontstash.Font;
|
||||
|
||||
// TODO: Seems that there is a vertical jitter bug when resizing a window in OpenGL. Seems like a driver bug.
|
||||
// From other peoples research it seems that disabling vsync when a resize event occurs fixes it.
|
||||
@ -55,6 +57,8 @@ var draw_frame: DrawFrame = undefined;
|
||||
var main_pipeline: sgl.Pipeline = .{};
|
||||
var linear_sampler: sg.Sampler = .{};
|
||||
var nearest_sampler: sg.Sampler = .{};
|
||||
var font_context: fontstash.Context = undefined;
|
||||
pub var font_resolution_scale: f32 = 1;
|
||||
|
||||
pub fn init(options: Options) !void {
|
||||
draw_frame.init();
|
||||
@ -119,10 +123,19 @@ pub fn init(options: Options) !void {
|
||||
.mipmap_filter = .NEAREST,
|
||||
.label = "nearest-sampler",
|
||||
});
|
||||
|
||||
const dpi_scale = sapp.dpiScale();
|
||||
const atlas_size = 512;
|
||||
const atlas_dim = std.math.ceilPowerOfTwoAssert(u32, @intFromFloat(atlas_size * dpi_scale));
|
||||
font_context = try fontstash.Context.init(.{
|
||||
.width = @intCast(atlas_dim),
|
||||
.height = @intCast(atlas_dim),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
imgui.shutdown();
|
||||
font_context.deinit();
|
||||
sgl.shutdown();
|
||||
sg.shutdown();
|
||||
}
|
||||
@ -142,6 +155,7 @@ pub fn beginFrame() void {
|
||||
.dpi_scale = sapp.dpiScale()
|
||||
});
|
||||
|
||||
font_context.clearState();
|
||||
sgl.defaults();
|
||||
sgl.matrixModeProjection();
|
||||
sgl.ortho(0, draw_frame.screen_size.x, draw_frame.screen_size.y, 0, -1, 1);
|
||||
@ -166,6 +180,8 @@ pub fn endFrame() void {
|
||||
}
|
||||
};
|
||||
|
||||
font_context.flush();
|
||||
|
||||
{
|
||||
sg.beginPass(.{
|
||||
.action = pass_action,
|
||||
@ -260,3 +276,35 @@ pub fn popScissor() void {
|
||||
|
||||
sgl.scissorRectf(rect.pos.x, rect.pos.y, rect.size.x, rect.size.y, true);
|
||||
}
|
||||
|
||||
pub fn addFont(name: [*c]const u8, data: []const u8) !Font.Id {
|
||||
return try font_context.addFont(name, data);
|
||||
}
|
||||
|
||||
pub const DrawTextOptions = struct {
|
||||
font: Font.Id,
|
||||
size: f32 = 16,
|
||||
color: Vec4 = rgb(255, 255, 255),
|
||||
};
|
||||
|
||||
pub fn drawText(position: Vec2, text: []const u8, opts: DrawTextOptions) void {
|
||||
pushTransform(.{ .x = 0, .y = 0}, 1/font_resolution_scale);
|
||||
defer popTransform();
|
||||
|
||||
font_context.setFont(opts.font);
|
||||
font_context.setSize(opts.size * font_resolution_scale);
|
||||
font_context.setAlign(.{ .x = .left, .y = .top });
|
||||
font_context.setSpacing(0);
|
||||
|
||||
const r: u8 = @intFromFloat(opts.color.x * 255);
|
||||
const g: u8 = @intFromFloat(opts.color.y * 255);
|
||||
const b: u8 = @intFromFloat(opts.color.z * 255);
|
||||
const a: u8 = @intFromFloat(opts.color.w * 255);
|
||||
const color: u32 = r | (@as(u32, g) << 8) | (@as(u32, b) << 16) | (@as(u32, a) << 24);
|
||||
font_context.setColor(color);
|
||||
font_context.drawText(
|
||||
position.x * font_resolution_scale,
|
||||
position.y * font_resolution_scale,
|
||||
text
|
||||
);
|
||||
}
|
||||
|
||||
@ -179,6 +179,8 @@ fn sokolFrame(self: *Engine) !void {
|
||||
const ctx = ScreenScalar.push(window_size, self.game.canvas_size);
|
||||
defer ctx.pop();
|
||||
|
||||
Graphics.font_resolution_scale = ctx.scale;
|
||||
|
||||
try self.game.tick(Frame{
|
||||
.time_ns = time_passed,
|
||||
.dt_ns = dt_ns,
|
||||
|
||||
@ -6,6 +6,10 @@ const rgb = Math.rgb;
|
||||
|
||||
const ScreenScalar = @This();
|
||||
|
||||
// TODO: Implement a fractional pixel perfect scalar
|
||||
// Based on this video: https://www.youtube.com/watch?v=d6tp43wZqps
|
||||
// And this blog: https://colececil.dev/blog/2017/scaling-pixel-art-without-destroying-it/
|
||||
|
||||
window_size: Vec2,
|
||||
translation: Vec2,
|
||||
scale: f32,
|
||||
|
||||
@ -50,12 +50,19 @@ pub fn tick(self: *Game, frame: Engine.Frame) !void {
|
||||
|
||||
self.player = self.player.add(dir.multiplyScalar(50 * frame.dt));
|
||||
|
||||
const regular_font = self.assets.font_id.get(.regular);
|
||||
|
||||
Gfx.drawRectangle(.init(0, 0), self.canvas_size, rgb(20, 20, 20));
|
||||
const size = Vec2.init(20, 20);
|
||||
Gfx.drawRectangle(self.player.sub(size.divideScalar(2)), size, rgb(200, 20, 20));
|
||||
if (dir.x != 0 or dir.y != 0) {
|
||||
Gfx.drawRectanglOutline(self.player.sub(size.divideScalar(2)), size, rgb(20, 200, 20), 3);
|
||||
}
|
||||
|
||||
Gfx.drawText(self.player, "Player", .{
|
||||
.font = regular_font,
|
||||
.size = 10
|
||||
});
|
||||
}
|
||||
|
||||
pub fn debug(self: *Game) !void {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user