diff --git a/src/Canvas.zig b/src/Canvas.zig index 21b9aba..bec812c 100644 --- a/src/Canvas.zig +++ b/src/Canvas.zig @@ -35,6 +35,7 @@ redraw_throttle_ms: u32 = 50, frame_index: u64 = 0, _zoom: f32 = 1, +_rendering_quality: f32 = 100.0, _last_redraw_time_ms: i64 = 0, // Метка последней перерисовки чтобы ограничить частоту _visible_rect: ?Rect_i = null, _redraw_pending: bool = false, @@ -59,9 +60,9 @@ pub fn deinit(self: *Canvas) void { fn redraw(self: *Canvas) !void { const full = self.getZoomedImageSize(); - const vis: Rect_i = self._visible_rect orelse Rect_i{ .x = 0, .y = 0, .w = 0, .h = 0 }; + const vis_full: Rect_i = self._visible_rect orelse Rect_i{ .x = 0, .y = 0, .w = 0, .h = 0 }; - if (vis.w == 0 or vis.h == 0) { + if (vis_full.w == 0 or vis_full.h == 0) { if (self.texture) |tex| { dvui.Texture.destroyLater(tex); self.texture = null; @@ -69,11 +70,42 @@ fn redraw(self: *Canvas) !void { return; } - const canvas_size: Size_i = .{ .w = full.w, .h = full.h }; + // Качество рендеринга задаётся в процентах площади (1–100), + // при этом фактически уменьшаем ширину/высоту холста на корень из этой доли. + const quality_percent: f32 = self.getRenderingQuality(); + const quality_area: f32 = quality_percent / 100.0; + const quality_side: f32 = std.math.sqrt(quality_area); + const scale: f32 = std.math.clamp(quality_side, 0.01, 1.0); + + const canvas_size: Size_i = .{ + .w = @max(@as(u32, 1), @as(u32, @intFromFloat(@as(f32, @floatFromInt(full.w)) * scale))), + .h = @max(@as(u32, 1), @as(u32, @intFromFloat(@as(f32, @floatFromInt(full.h)) * scale))), + }; + + var vis_scaled = Rect_i{ + .x = @as(u32, @intFromFloat(@as(f32, @floatFromInt(vis_full.x)) * scale)), + .y = @as(u32, @intFromFloat(@as(f32, @floatFromInt(vis_full.y)) * scale)), + .w = @max(@as(u32, 1), @as(u32, @intFromFloat(@as(f32, @floatFromInt(vis_full.w)) * scale))), + .h = @max(@as(u32, 1), @as(u32, @intFromFloat(@as(f32, @floatFromInt(vis_full.h)) * scale))), + }; + + if (vis_scaled.x >= canvas_size.w or vis_scaled.y >= canvas_size.h) { + if (self.texture) |tex| { + dvui.Texture.destroyLater(tex); + self.texture = null; + } + return; + } + + const max_vis_w: u32 = canvas_size.w - vis_scaled.x; + const max_vis_h: u32 = canvas_size.h - vis_scaled.y; + if (vis_scaled.w > max_vis_w) vis_scaled.w = max_vis_w; + if (vis_scaled.h > max_vis_h) vis_scaled.h = max_vis_h; + const new_texture = if (self.draw_document) - self.render_engine.render(self.document, canvas_size, vis) catch null + self.render_engine.render(self.document, canvas_size, vis_scaled) catch null else - self.render_engine.example(canvas_size, vis) catch null; + self.render_engine.example(canvas_size, vis_scaled) catch null; if (new_texture) |tex| { if (self.texture) |old_tex| { @@ -114,6 +146,15 @@ pub fn getZoom(self: Canvas) f32 { return self._zoom; } +pub fn setRenderingQuality(self: *Canvas, value: f32) void { + self._rendering_quality = std.math.clamp(value, 1.0, 100.0); + self.requestRedraw(); +} + +pub fn getRenderingQuality(self: Canvas) f32 { + return self._rendering_quality; +} + pub fn requestRedraw(self: *Canvas) void { self._redraw_pending = true; } diff --git a/src/ui/left_panel.zig b/src/ui/left_panel.zig index eb93771..f4f2b1f 100644 --- a/src/ui/left_panel.zig +++ b/src/ui/left_panel.zig @@ -176,6 +176,18 @@ pub fn leftPanel(ctx: *WindowContext) void { canvas.requestRedraw(); } if (dvui.checkbox(@src(), &canvas.show_render_stats, "Show stats", .{})) {} + { + dvui.label(@src(), "Rendering quality", .{}, .{}); + var quality = canvas.getRenderingQuality(); + if (dvui.sliderEntry( + @src(), + "{d:0.0}%", + .{ .value = &quality, .min = 1.0, .max = 100.0, .interval = 1.0 }, + .{ .expand = .horizontal }, + )) { + canvas.setRenderingQuality(quality); + } + } if (!canvas.draw_document) { if (dvui.button(@src(), if (doc.cpu_render.type == .Gradient) "Gradient" else "Squares", .{}, .{})) { if (doc.cpu_render.type == .Gradient) {