diff --git a/src/Canvas.zig b/src/Canvas.zig index c388bbb..77b422d 100644 --- a/src/Canvas.zig +++ b/src/Canvas.zig @@ -42,8 +42,6 @@ pub fn deinit(self: *Canvas) void { /// Заполнить canvas градиентом pub fn redrawExample(self: *Canvas) !void { const full = self.getScaledImageSize(); - const full_w: u32 = full.w; - const full_h: u32 = full.h; const vis: ImageRect = self._visible_rect orelse ImageRect{ .x = 0, .y = 0, .w = 0, .h = 0 }; @@ -55,58 +53,20 @@ pub fn redrawExample(self: *Canvas) !void { return; } - const width: u32 = vis.w; - const height: u32 = vis.h; + const new_texture = self.render_engine.example(.{ .w = full.w, .h = full.h }, vis) catch null; - // const new_texture = self.render_engine.example(width, height); - - // Выделить буфер пиксельных данных - const pixels = try self.allocator.alloc(Color.PMA, @as(usize, width) * height); - defer self.allocator.free(pixels); - - std.debug.print("w={any}, fw={any};\th={any}, fh={any}\n", .{ width, full_w, height, full_h }); - - var y: u32 = 0; - while (y < height) : (y += 1) { - var x: u32 = 0; - while (x < width) : (x += 1) { - const gx: u32 = vis.x + x; - const gy: u32 = vis.y + y; - - const denom_x: f32 = if (full_w > 1) @as(f32, @floatFromInt(full_w - 1)) else 1; - const denom_y: f32 = if (full_h > 1) @as(f32, @floatFromInt(full_h - 1)) else 1; - const fx: f32 = @as(f32, @floatFromInt(gx)) / denom_x; - const fy: f32 = @as(f32, @floatFromInt(gy)) / denom_y; - const factor: f32 = std.math.clamp((fx + fy) / 2, 0, 1); - - const r_f: f32 = @as(f32, @floatFromInt(self.gradient_start.r)) + factor * (@as(f32, @floatFromInt(self.gradient_end.r)) - @as(f32, @floatFromInt(self.gradient_start.r))); - const g_f: f32 = @as(f32, @floatFromInt(self.gradient_start.g)) + factor * (@as(f32, @floatFromInt(self.gradient_end.g)) - @as(f32, @floatFromInt(self.gradient_start.g))); - const b_f: f32 = @as(f32, @floatFromInt(self.gradient_start.b)) + factor * (@as(f32, @floatFromInt(self.gradient_end.b)) - @as(f32, @floatFromInt(self.gradient_start.b))); - - const r: u8 = @intFromFloat(std.math.clamp(r_f, 0, 255)); - const g: u8 = @intFromFloat(std.math.clamp(g_f, 0, 255)); - const b: u8 = @intFromFloat(std.math.clamp(b_f, 0, 255)); - pixels[y * width + x] = .{ .r = r, .g = g, .b = b, .a = 255 }; + if (new_texture) |tex| { + // Удалить старую текстуру + if (self.texture) |old_tex| { + dvui.Texture.destroyLater(old_tex); } - } - // Удалить старую текстуру - if (self.texture) |tex| { - dvui.Texture.destroyLater(tex); + self.texture = tex; } - - // Создать новую текстуру из пиксельных данных - self.texture = try dvui.textureCreate(pixels, width, height, .nearest); } -/// Заполнить canvas случайным градиентом +// Ресетнуть example изображение в renderEngine pub fn exampleReset(self: *Canvas) !void { - // Сгенерировать случайные цвета градиента - var prng = std.Random.DefaultPrng.init(@intCast(std.time.microTimestamp())); - const random = prng.random(); - self.gradient_start = Color.PMA{ .r = random.int(u8), .g = random.int(u8), .b = random.int(u8), .a = 255 }; - self.gradient_end = Color.PMA{ .r = random.int(u8), .g = random.int(u8), .b = random.int(u8), .a = 255 }; - self.render_engine.exampleReset(); try self.redrawExample(); } diff --git a/src/WindowContext.zig b/src/WindowContext.zig index ff07de9..da4a22b 100644 --- a/src/WindowContext.zig +++ b/src/WindowContext.zig @@ -7,6 +7,7 @@ const WindowContext = @This(); allocator: std.mem.Allocator, canvas: Canvas, cpu_render: *CpuRenderEngine, +frame_index: u64, pub fn init(allocator: std.mem.Allocator) !WindowContext { var self: WindowContext = undefined; @@ -18,6 +19,8 @@ pub fn init(allocator: std.mem.Allocator) !WindowContext { self.canvas = Canvas.init(allocator, self.cpu_render.renderEngine()); + self.frame_index = 0; + return self; } diff --git a/src/main.zig b/src/main.zig index bd82ebd..3a4df5a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -33,7 +33,6 @@ pub fn main() !void { defer ctx.deinit(); var interrupted = false; - main_loop: while (true) { // beginWait coordinates with waitTime below to run frames only when needed const nstime = win.beginWait(interrupted); @@ -89,12 +88,12 @@ fn gui_frame(ctx: *WindowContext) bool { var left_panel = dvui.box(@src(), .{ .dir = .vertical }, .{ .expand = .vertical, .min_size_content = .{ .w = 200 }, .background = true }); { dvui.label(@src(), "Tools", .{}, .{}); - if (dvui.button(@src(), "Fill Random Color", .{}, .{})) { + if (dvui.button(@src(), "Fill Random Color", .{}, .{}) or ctx.frame_index == 0) { canvas.exampleReset() catch |err| { std.debug.print("Error filling canvas: {}\n", .{err}); }; - canvas.pos = .{ .x = 400, .y = 400 }; - canvas.setZoom(dvui.windowNaturalScale()); + ctx.canvas.pos = .{ .x = 400, .y = 400 }; + ctx.canvas.setZoom(dvui.windowNaturalScale()); } if (dvui.checkbox(@src(), &canvas.native_scaling, "Scaling", .{})) {} } @@ -222,5 +221,7 @@ fn gui_frame(ctx: *WindowContext) bool { } back.deinit(); + ctx.frame_index += 1; + return true; } diff --git a/src/render/CpuRenderEngine.zig b/src/render/CpuRenderEngine.zig index ffa2120..5b916c5 100644 --- a/src/render/CpuRenderEngine.zig +++ b/src/render/CpuRenderEngine.zig @@ -35,10 +35,43 @@ pub fn exampleReset(self: *CpuRenderEngine) void { } pub fn example(self: CpuRenderEngine, canvas_size: ImageSize, visible_rect: ImageRect) !?dvui.Texture { - _ = self; - _ = canvas_size; - _ = visible_rect; - return null; + const full_w = canvas_size.w; + const full_h = canvas_size.h; + + const width = visible_rect.w; + const height = visible_rect.h; + + // Выделить буфер пиксельных данных + const pixels = try self._allocator.alloc(Color.PMA, @as(usize, width) * height); + defer self._allocator.free(pixels); + + std.debug.print("w={any}, fw={any};\th={any}, fh={any}\n", .{ width, full_w, height, full_h }); + + var y: u32 = 0; + while (y < height) : (y += 1) { + var x: u32 = 0; + while (x < width) : (x += 1) { + const gx: u32 = visible_rect.x + x; + const gy: u32 = visible_rect.y + y; + + const denom_x: f32 = if (full_w > 1) @as(f32, @floatFromInt(full_w - 1)) else 1; + const denom_y: f32 = if (full_h > 1) @as(f32, @floatFromInt(full_h - 1)) else 1; + const fx: f32 = @as(f32, @floatFromInt(gx)) / denom_x; + const fy: f32 = @as(f32, @floatFromInt(gy)) / denom_y; + const factor: f32 = std.math.clamp((fx + fy) / 2, 0, 1); + + const r_f: f32 = @as(f32, @floatFromInt(self.gradient_start.r)) + factor * (@as(f32, @floatFromInt(self.gradient_end.r)) - @as(f32, @floatFromInt(self.gradient_start.r))); + const g_f: f32 = @as(f32, @floatFromInt(self.gradient_start.g)) + factor * (@as(f32, @floatFromInt(self.gradient_end.g)) - @as(f32, @floatFromInt(self.gradient_start.g))); + const b_f: f32 = @as(f32, @floatFromInt(self.gradient_start.b)) + factor * (@as(f32, @floatFromInt(self.gradient_end.b)) - @as(f32, @floatFromInt(self.gradient_start.b))); + + const r: u8 = @intFromFloat(std.math.clamp(r_f, 0, 255)); + const g: u8 = @intFromFloat(std.math.clamp(g_f, 0, 255)); + const b: u8 = @intFromFloat(std.math.clamp(b_f, 0, 255)); + pixels[y * width + x] = .{ .r = r, .g = g, .b = b, .a = 255 }; + } + } + + return try dvui.textureCreate(pixels, width, height, .nearest); } pub fn renderEngine(self: *CpuRenderEngine) RenderEngine {