From 9fa13fa9130733ebbfac6668ab731fc59e93dd9f Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Sun, 1 Mar 2026 17:19:52 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=82=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=20=D0=BA=D0=B0=D0=B4=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Canvas.zig | 14 +++--- src/WindowContext.zig | 3 -- src/render/CpuRenderEngine.zig | 13 +++++- src/render/RenderEngine.zig | 7 +++ src/render/RenderStats.zig | 3 ++ src/ui/canvas_view.zig | 82 ++++++++++++++++++++++++++-------- src/ui/frame.zig | 1 - src/ui/left_panel.zig | 4 ++ 8 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 src/render/RenderStats.zig diff --git a/src/Canvas.zig b/src/Canvas.zig index de92ee4..91090d7 100644 --- a/src/Canvas.zig +++ b/src/Canvas.zig @@ -24,17 +24,20 @@ scroll: dvui.ScrollInfo = .{ .horizontal = .auto, }, native_scaling: bool = true, -redraw_throttle_ms: u32 = 50, -_visible_rect: ?Rect_i = null, -_zoom: f32 = 1, -_redraw_pending: bool = false, -_last_redraw_time_ms: i64 = 0, cursor_document_point: ?Point2_f = null, draw_document: bool = true, +show_render_stats: bool = true, /// Rect тулбара (из предыдущего кадра) для исключения кликов по нему из handleCanvasMouse. toolbar_rect_scale: ?dvui.RectScale = null, /// Rect панели свойств (из предыдущего кадра) для исключения кликов по нему из handleCanvasMouse. properties_rect_scale: ?dvui.RectScale = null, +redraw_throttle_ms: u32 = 50, +frame_index: u64 = 0, + +_zoom: f32 = 1, +_last_redraw_time_ms: i64 = 0, // Метка последней перерисовки чтобы ограничить частоту +_visible_rect: ?Rect_i = null, +_redraw_pending: bool = false, pub fn init(allocator: std.mem.Allocator, document: *Document, engine: RenderEngine) Canvas { return .{ @@ -80,6 +83,7 @@ fn redraw(self: *Canvas) !void { self.texture = tex; } self._last_redraw_time_ms = std.time.milliTimestamp(); + self.frame_index += 1; } pub fn exampleReset(self: *Canvas) !void { diff --git a/src/WindowContext.zig b/src/WindowContext.zig index b096d47..734d1c8 100644 --- a/src/WindowContext.zig +++ b/src/WindowContext.zig @@ -45,17 +45,14 @@ pub const OpenDocument = struct { }; allocator: std.mem.Allocator, -frame_index: u64, documents: std.ArrayList(*OpenDocument), active_document_index: ?usize, pub fn init(allocator: std.mem.Allocator) !WindowContext { - const frame_index: u64 = 0; const documents = std.ArrayList(*OpenDocument).empty; const active_document_index: ?usize = null; return .{ .allocator = allocator, - .frame_index = frame_index, .documents = documents, .active_document_index = active_document_index, }; diff --git a/src/render/CpuRenderEngine.zig b/src/render/CpuRenderEngine.zig index ff9fedd..6ec4187 100644 --- a/src/render/CpuRenderEngine.zig +++ b/src/render/CpuRenderEngine.zig @@ -5,6 +5,7 @@ const RenderEngine = @import("RenderEngine.zig").RenderEngine; const Document = @import("../models/Document.zig"); const basic_models = @import("../models/basic_models.zig"); const cpu_draw = @import("cpu/draw.zig"); +const RenderStats = @import("RenderStats.zig"); const Size_i = basic_models.Size_i; const Rect_i = basic_models.Rect_i; const Allocator = std.mem.Allocator; @@ -17,14 +18,18 @@ const Type = enum { }; type: Type, -_allocator: Allocator, gradient_start: Color.PMA = .{ .r = 0, .g = 0, .b = 0, .a = 255 }, gradient_end: Color.PMA = .{ .r = 255, .g = 255, .b = 255, .a = 255 }, +_allocator: Allocator, +_renderStats: RenderStats, pub fn init(allocator: Allocator, render_type: Type) CpuRenderEngine { return .{ ._allocator = allocator, .type = render_type, + ._renderStats = .{ + .render_time_ns = 0, + }, }; } @@ -182,7 +187,13 @@ pub fn renderDocument(self: *CpuRenderEngine, document: *const Document, canvas_ defer self._allocator.free(pixels); for (pixels) |*p| p.* = .{ .r = 255, .g = 255, .b = 255, .a = 255 }; + var t = try std.time.Timer.start(); try cpu_draw.drawDocument(pixels, width, height, visible_rect, document, canvas_size, self._allocator); + self._renderStats.render_time_ns = t.read(); return try dvui.textureCreate(pixels, width, height, .nearest); } + +pub fn getStats(self: CpuRenderEngine) RenderStats { + return self._renderStats; +} diff --git a/src/render/RenderEngine.zig b/src/render/RenderEngine.zig index 12c1df4..e06b41f 100644 --- a/src/render/RenderEngine.zig +++ b/src/render/RenderEngine.zig @@ -2,6 +2,7 @@ const dvui = @import("dvui"); const CpuRenderEngine = @import("CpuRenderEngine.zig"); const Document = @import("../models/Document.zig"); const basic_models = @import("../models/basic_models.zig"); +const RenderStats = @import("RenderStats.zig"); pub const RenderEngine = union(enum) { cpu: *CpuRenderEngine, @@ -18,6 +19,12 @@ pub const RenderEngine = union(enum) { }; } + pub fn getStats(self: RenderEngine) RenderStats { + return switch (self) { + .cpu => |cpu_r| cpu_r.getStats(), + }; + } + /// Растеризует документ в текстуру. pub fn render(self: RenderEngine, document: *const Document, canvas_size: basic_models.Size_i, visible_rect: basic_models.Rect_i) !?dvui.Texture { return switch (self) { diff --git a/src/render/RenderStats.zig b/src/render/RenderStats.zig new file mode 100644 index 0000000..04df7f0 --- /dev/null +++ b/src/render/RenderStats.zig @@ -0,0 +1,3 @@ +const RenderStats = @This(); + +render_time_ns: u64, // Время рендера кадра в микросекундах diff --git a/src/ui/canvas_view.zig b/src/ui/canvas_view.zig index 789988b..3cf8e0e 100644 --- a/src/ui/canvas_view.zig +++ b/src/ui/canvas_view.zig @@ -7,6 +7,7 @@ const Property = @import("../models/Property.zig").Property; const PropertyData = @import("../models/Property.zig").Data; const Rect_i = @import("../models/basic_models.zig").Rect_i; const Tool = @import("../toolbar/Tool.zig"); +const RenderStats = @import("../render/RenderStats.zig"); pub fn canvasView(canvas: *Canvas, selected_object_id: ?u64, content_rect_scale: dvui.RectScale) void { var textured = dvui_ext.texturedBox(content_rect_scale, dvui.Rect.all(20)); @@ -36,23 +37,27 @@ pub fn canvasView(canvas: *Canvas, selected_object_id: ?u64, content_rect_scale: const scroll_parent = dvui.parentGet(); dvui.parentSet(overlay_parent); + const vbar = scroll.vbar; + const hbar = scroll.hbar; + if (vbar != null) { + + // std.debug.print("{any}", .{vbar.?.data()}); + } + if (hbar != null) { + // std.debug.print("{any}", .{hbar.?.data()}); + } + // Тулбар поверх scroll var toolbar_box = dvui.box( @src(), .{ .dir = .horizontal }, - .{ - .expand = .none, - .background = false, - .gravity_x = 0.0, - .gravity_y = 0.0, - .margin = dvui.Rect{ .x = 16, .y = 16 }, - }, + .{}, ); { drawToolbar(canvas); + // Сохраняем rect тулбара для следующего кадра — в handleCanvasMouse исключаем из него клики + canvas.toolbar_rect_scale = toolbar_box.data().contentRectScale(); } - // Сохраняем rect тулбара для следующего кадра — в handleCanvasMouse исключаем из него клики - canvas.toolbar_rect_scale = toolbar_box.data().contentRectScale(); toolbar_box.deinit(); // Панель свойств поверх scroll (правый верхний угол) @@ -61,24 +66,20 @@ pub fn canvasView(canvas: *Canvas, selected_object_id: ?u64, content_rect_scale: var properties_box = dvui.box( @src(), .{ .dir = .horizontal }, - .{ - .expand = .none, - .background = false, - .gravity_x = 1.0, - .gravity_y = 0.0, - .margin = dvui.Rect{ .w = 32, .y = 16, .h = 100 }, - }, + .{}, ); { drawPropertiesPanel(canvas, obj); + // Сохраняем rect панели свойств для следующего кадра — в handleCanvasMouse исключаем из него клики + canvas.properties_rect_scale = properties_box.data().contentRectScale(); } - // Сохраняем rect панели свойств для следующего кадра — в handleCanvasMouse исключаем из него клики - canvas.properties_rect_scale = properties_box.data().contentRectScale(); properties_box.deinit(); } } - dvui.label(@src(), "Canvas", .{}, .{ .gravity_x = 0.5, .gravity_y = 0.0 }); + drawCanvasLabelPanel(); + if (canvas.show_render_stats) + drawStatsPanel(canvas.render_engine.getStats(), canvas.frame_index); if (canvas.properties_rect_scale) |prs| { for (dvui.events()) |*e| { @@ -278,6 +279,7 @@ fn drawToolbar(canvas: *Canvas) void { .corner_radius = dvui.Rect.all(8), .background = true, .color_fill = dvui.Color.black.opacity(0.2), + .margin = dvui.Rect{ .x = 16, .y = 16 }, }, ); { @@ -312,6 +314,7 @@ fn drawPropertiesPanel(canvas: *Canvas, selected_object: *Document.Object) void .background = true, .color_fill = dvui.Color.black.opacity(0.2), .min_size_content = .{ .w = 220 }, + .margin = dvui.Rect{ .w = 32, .y = 16, .h = 100 }, }, ); { @@ -332,6 +335,47 @@ fn drawPropertiesPanel(canvas: *Canvas, selected_object: *Document.Object) void panel.deinit(); } +fn drawCanvasLabelPanel() void { + var panel = dvui.box( + @src(), + .{ .dir = .vertical }, + .{ + .gravity_x = 0.5, + .gravity_y = 0.0, + .padding = dvui.Rect.all(8), + .corner_radius = dvui.Rect.all(8), + .background = true, + .color_fill = dvui.Color.black.opacity(0.2), + .margin = dvui.Rect{ .x = 16, .y = 16 }, + }, + ); + { + dvui.label(@src(), "Canvas", .{}, .{}); + } + panel.deinit(); +} + +fn drawStatsPanel(stats: RenderStats, frame_index: u64) void { + var panel = dvui.box( + @src(), + .{ .dir = .vertical }, + .{ + .gravity_x = 0.0, + .gravity_y = 1.0, + .padding = dvui.Rect.all(8), + .corner_radius = dvui.Rect.all(8), + .background = true, + .color_fill = dvui.Color.black.opacity(0.2), + .margin = dvui.Rect{ .x = 16, .h = 16 }, + }, + ); + { + dvui.label(@src(), "Frame time: {}ms", .{stats.render_time_ns / std.time.ns_per_ms}, .{}); + dvui.label(@src(), "Frame index: {}", .{frame_index}, .{}); + } + panel.deinit(); +} + fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Property, row_index: usize) void { const row_id: usize = row_index * 16; var row = dvui.box( diff --git a/src/ui/frame.zig b/src/ui/frame.zig index 009c559..8326f38 100644 --- a/src/ui/frame.zig +++ b/src/ui/frame.zig @@ -30,6 +30,5 @@ pub fn guiFrame(ctx: *WindowContext) bool { } root.deinit(); - ctx.frame_index += 1; return true; } diff --git a/src/ui/left_panel.zig b/src/ui/left_panel.zig index 9e72314..20f97b6 100644 --- a/src/ui/left_panel.zig +++ b/src/ui/left_panel.zig @@ -175,6 +175,7 @@ pub fn leftPanel(ctx: *WindowContext) void { if (dvui.checkbox(@src(), &canvas.draw_document, "Draw document", .{})) { canvas.requestRedraw(); } + if (dvui.checkbox(@src(), &canvas.show_render_stats, "Show stats", .{})) {} if (!canvas.draw_document) { if (dvui.button(@src(), if (doc.cpu_render.type == .Gradient) "Gradient" else "Squares", .{}, .{})) { if (doc.cpu_render.type == .Gradient) { @@ -188,6 +189,9 @@ pub fn leftPanel(ctx: *WindowContext) void { if (dvui.button(@src(), "Add random shapes", .{}, .{})) { canvas.addRandomShapes() catch {}; } + if (dvui.button(@src(), "Request redraw", .{}, .{})) { + canvas.requestRedraw(); + } } else { dvui.label(@src(), "No document", .{}, .{}); }