rework UI

This commit is contained in:
Rokas Puzonas 2025-03-10 01:01:13 +02:00
parent a6a66d99fd
commit 877f8034c7
15 changed files with 1635 additions and 2269 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
.zig-cache
zig-out
.vscode
.vscode
profile.json

View File

@ -90,6 +90,11 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize,
});
const profiler_dep = b.dependency("profiler.zig", .{
.target = target,
.optimize = optimize,
});
const stb_image_lib = buildStbImage(b);
const cute_aseprite_lib = buildCuteAseprite(b, raylib_dep);
@ -114,6 +119,9 @@ pub fn build(b: *std.Build) !void {
exe.root_module.addImport("known-folders", known_folders);
exe.root_module.addImport("ini", ini);
// TODO: Add flag to disable in release
exe.root_module.addImport("profiler", profiler_dep.module("profiler"));
const external_compiler_support_dir = try std.process.getEnvVarOwned(b.allocator, "NIEXTCCOMPILERSUPP");
exe.addSystemIncludePath(.{ .cwd_relative = try std.fs.path.join(b.allocator, &.{ external_compiler_support_dir, "include" }) });

View File

@ -2,19 +2,16 @@
.name = "Baigiamasis projektas",
.version = "0.1.0",
.dependencies = .{
.@"raylib-zig" = .{
.url = "https://github.com/Not-Nik/raylib-zig/archive/43d15b05c2b97cab30103fa2b46cff26e91619ec.tar.gz",
.hash = "12204a223b19043e17b79300413d02f60fc8004c0d9629b8d8072831e352a78bf212"
.dependencies = .{ .@"raylib-zig" = .{ .url = "https://github.com/Not-Nik/raylib-zig/archive/43d15b05c2b97cab30103fa2b46cff26e91619ec.tar.gz", .hash = "12204a223b19043e17b79300413d02f60fc8004c0d9629b8d8072831e352a78bf212" }, .@"known-folders" = .{
.url = "git+https://github.com/ziglibs/known-folders.git#1cceeb70e77dec941a4178160ff6c8d05a74de6f",
.hash = "12205f5e7505c96573f6fc5144592ec38942fb0a326d692f9cddc0c7dd38f9028f29",
}, .ini = .{
.url = "https://github.com/ziglibs/ini/archive/e18d36665905c1e7ba0c1ce3e8780076b33e3002.tar.gz",
.hash = "1220b0979ea9891fa4aeb85748fc42bc4b24039d9c99a4d65d893fb1c83e921efad8",
}, .@"profiler.zig" = .{
.url = "git+https://github.com/lassade/profiler.zig.git#d066d066c36c4eebd494babf15c1cdbd2d512b12",
.hash = "122097461acc2064f5f89b85d76d2a02232579864b17604617a333789c892f2d262f",
},
.@"known-folders" = .{
.url = "git+https://github.com/ziglibs/known-folders.git#1cceeb70e77dec941a4178160ff6c8d05a74de6f",
.hash = "12205f5e7505c96573f6fc5144592ec38942fb0a326d692f9cddc0c7dd38f9028f29",
},
.@"ini" = .{
.url = "https://github.com/ziglibs/ini/archive/e18d36665905c1e7ba0c1ce3e8780076b33e3002.tar.gz",
.hash = "1220b0979ea9891fa4aeb85748fc42bc4b24039d9c99a4d65d893fb1c83e921efad8",
}
},
.paths = .{

File diff suppressed because it is too large Load Diff

View File

@ -5,15 +5,38 @@ const FontFace = @import("./font-face.zig");
const Aseprite = @import("cute_aseprite");
const assert = std.debug.assert;
const log = std.log.scoped(.assets);
pub const FontId = enum {
text
pub const FontVariant = enum {
regular,
regular_italic,
bold,
bold_italic,
thin,
thin_italic
};
var loaded_fonts: std.BoundedArray(rl.Font, 32) = .{};
pub const FontId = struct {
variant: FontVariant,
size: f32,
const FontArray = std.EnumArray(FontId, FontFace);
var fonts: FontArray = FontArray.initUndefined();
pub fn eql(self: FontId, other: FontId) bool {
return self.variant == other.variant and self.size == other.size;
}
};
const LoadedFont = struct {
id: FontId,
font: rl.Font,
generation: u64,
};
const FontTTFArray = std.EnumArray(FontVariant, []const u8);
var font_ttfs: FontTTFArray = undefined;
const LoadedFontsArray = std.BoundedArray(LoadedFont, std.meta.fields(FontVariant).len * 8);
var current_font_generation: u64 = 0;
var loaded_fonts: LoadedFontsArray = .{ };
pub var grab_texture: struct {
normal: rl.Texture2D,
@ -24,16 +47,47 @@ pub var grab_texture: struct {
pub var dropdown_arrow: rl.Texture2D = undefined;
pub fn font(font_id: FontId) FontFace {
return fonts.get(font_id);
var found_font: ?LoadedFont = null;
for (loaded_fonts.slice()) |*loaded_font| {
if (font_id.eql(loaded_font.id)) {
loaded_font.generation = current_font_generation;
found_font = loaded_font.*;
}
}
if (found_font == null) {
const raylib_font = loadFont(
font_ttfs.get(font_id.variant),
@intFromFloat(@round(font_id.size))
) catch rl.getFontDefault();
found_font = LoadedFont{
.id = font_id,
.font = raylib_font,
.generation = current_font_generation
};
loaded_fonts.append(found_font.?) catch {
log.warn("Failed to append font, font cache is full", .{});
};
}
return FontFace{
.line_height = 1.2,
.font = found_font.?.font,
};
}
pub fn init(allocator: std.mem.Allocator) !void {
const roboto_regular = @embedFile("./assets/fonts/roboto/Roboto-Regular.ttf");
font_ttfs = FontTTFArray.init(.{
.regular = @embedFile("./assets/fonts/roboto/Roboto-Regular.ttf"),
.regular_italic = @embedFile("./assets/fonts/roboto/Roboto-Italic.ttf"),
const default_font = try loadFont(roboto_regular, 16);
.bold = @embedFile("./assets/fonts/roboto/Roboto-Bold.ttf"),
.bold_italic = @embedFile("./assets/fonts/roboto/Roboto-BoldItalic.ttf"),
fonts = FontArray.init(.{
.text = FontFace{ .font = default_font, .line_height = 1.2 }
.thin = @embedFile("./assets/fonts/roboto/Roboto-Thin.ttf"),
.thin_italic = @embedFile("./assets/fonts/roboto/Roboto-ThinItalic.ttf")
});
{
@ -86,22 +140,36 @@ fn loadFont(ttf_data: []const u8, font_size: u32) !rl.Font {
codepoints.appendAssumeCapacity(codepoint);
}
const loaded_font = rl.loadFontFromMemory(".ttf", ttf_data, @intCast(font_size), codepoints.slice());
if (!loaded_font.isReady()) {
const raylib_font = rl.loadFontFromMemory(".ttf", ttf_data, @intCast(font_size), codepoints.slice());
if (!raylib_font.isReady()) {
return error.LoadFontFromMemory;
}
loaded_fonts.appendAssumeCapacity(loaded_font);
return raylib_font;
}
return loaded_font;
pub fn deinitUnusedFonts() void {
var i: usize = 0;
while (i < loaded_fonts.len) {
const loaded_font = loaded_fonts.buffer[i];
if (loaded_font.generation < current_font_generation) {
loaded_font.font.unload();
_ = loaded_fonts.swapRemove(i);
} else {
i += 1;
}
}
current_font_generation += 1;
}
pub fn deinit(allocator: std.mem.Allocator) void {
_ = allocator;
for (loaded_fonts.slice()) |loaded_font| {
loaded_font.unload();
loaded_font.font.unload();
}
loaded_fonts.len = 0;
grab_texture.active.unload();
grab_texture.hot.unload();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -60,7 +60,6 @@ pub fn drawTextEx(self: @This(), text: []const u8, position: rl.Vector2, tint: r
var iter = std.unicode.Utf8Iterator{ .bytes = text, .i = 0 };
while (iter.nextCodepoint()) |codepoint| {
if (codepoint == '\n') {
offset.x = 0;
offset.y += font_size * self.line_height;

View File

@ -1,19 +0,0 @@
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
out vec4 finalColor;
void main()
{
vec4 texelColor = texture(texture0, fragTexCoord)*colDiffuse*fragColor;
float luminance = dot(texelColor.rgb, vec3(0.2126, 0.7152, 0.0722));
gl_FragColor = vec4(luminance, luminance, luminance, texelColor.a);
}

View File

@ -3,12 +3,13 @@ const rl = @import("raylib");
const builtin = @import("builtin");
const Application = @import("./app.zig");
const Assets = @import("./assets.zig");
const Profiler = @import("./profiler.zig");
const Profiler = @import("./my-profiler.zig");
const Platform = @import("./platform.zig");
const raylib_h = @cImport({
@cInclude("stdio.h");
@cInclude("raylib.h");
});
const P = @import("profiler");
const log = std.log;
const profiler_enabled = builtin.mode == .Debug;
@ -65,6 +66,12 @@ fn raylibTraceLogCallback(logType: c_int, text: [*c]const u8, args: raylib_h.va_
}
pub fn main() !void {
try P.init(.{});
defer {
P.dump("profile.json") catch |err| std.log.err("profile dump failed: {}", .{err});
P.deinit();
}
Platform.init();
// TODO: Setup logging to a file
@ -156,8 +163,8 @@ pub fn main() !void {
defer app.deinit();
if (builtin.mode == .Debug) {
// try app.appendChannelFromDevice("Dev1/ai0");
try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin");
try app.appendChannelFromDevice("Dev1/ai0");
// try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin");
// try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_IjStim.bin");
// try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_IjStim.bin");
// try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_IjStim.bin");
@ -168,31 +175,52 @@ pub fn main() !void {
var profiler_shown = false;
if (profiler_enabled) {
const font_face = Assets.font(.text);
profiler = try Profiler.init(allocator, 10 * target_fps, @divFloor(std.time.ns_per_s, target_fps), font_face);
profiler = try Profiler.init(
allocator,
10 * target_fps,
@divFloor(std.time.ns_per_s, target_fps),
Assets.FontId{ .variant = .regular, .size = 16 }
);
}
rl.setExitKey(rl.KeyboardKey.key_null);
var last_font_cleanup_at = rl.getTime();
while (!rl.windowShouldClose() and !app.should_close) {
rl.beginDrawing();
defer rl.endDrawing();
if (profiler) |*p| {
p.start();
{
const zone = P.begin(@src(), "tick");
defer zone.end();
if (profiler) |*p| {
p.start();
}
try app.tick();
if (profiler) |*p| {
p.stop();
if (rl.isKeyPressed(.key_p) and rl.isKeyDown(.key_left_control)) {
profiler_shown = !profiler_shown;
}
if (profiler_shown) {
try p.showResults();
}
}
const now = rl.getTime();
if (now - last_font_cleanup_at > 10) {
Assets.deinitUnusedFonts();
last_font_cleanup_at = now;
}
}
try app.tick();
if (profiler) |*p| {
p.stop();
if (rl.isKeyPressed(.key_p) and rl.isKeyDown(.key_left_control)) {
profiler_shown = !profiler_shown;
}
if (profiler_shown) {
try p.showResults();
}
{
const zone = P.begin(@src(), "end draw");
defer zone.end();
rl.endDrawing();
}
}
}

View File

@ -1,9 +1,10 @@
const std = @import("std");
const rl = @import("raylib");
const Assets = @import("./assets.zig");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const FontId = Assets.FontId;
const FontFace = @import("./font-face.zig");
const srcery = @import("./srcery.zig");
const rect_utils = @import("./rect-utils.zig");
@ -14,9 +15,9 @@ history_head: usize,
started_at: i128,
ns_budget: u128,
font_face: FontFace,
font: FontId,
pub fn init(allocator: Allocator, data_points: usize, ns_budget: u128, font_face: FontFace) !@This() {
pub fn init(allocator: Allocator, data_points: usize, ns_budget: u128, font: FontId) !@This() {
return @This(){
.allocator = allocator,
.history = try allocator.alloc(u128, data_points),
@ -24,7 +25,7 @@ pub fn init(allocator: Allocator, data_points: usize, ns_budget: u128, font_face
.history_head = 0,
.started_at = 0,
.ns_budget = ns_budget,
.font_face = font_face,
.font = font,
};
}
@ -90,7 +91,8 @@ pub fn showResults(self: *const @This()) !void {
var layout_offset: f32 = 0;
const allocator = self.allocator;
const font_size = self.font_face.getSize();
const font_face = Assets.font(self.font);
const font_size = font_face.getSize();
const labels = .{
.{ "Min", @as(f32, @floatFromInt(min_time_taken)) },
@ -104,7 +106,7 @@ pub fn showResults(self: *const @This()) !void {
const min_time_str = try std.fmt.allocPrintZ(allocator, "{s}: {d:10.0}us ({d:.3}%)", .{ label_name, time_taken / std.time.ns_per_us, time_taken / ns_budget * 100 });
defer allocator.free(min_time_str);
self.font_face.drawText(min_time_str, .{ .x = content_rect.x, .y = content_rect.y + layout_offset }, color);
font_face.drawText(min_time_str, .{ .x = content_rect.x, .y = content_rect.y + layout_offset }, color);
layout_offset += font_size;
}
}

2287
src/ui.zig

File diff suppressed because it is too large Load Diff