diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..807d23b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "zig.testArgs": [ + "build", + "test", + "-Dtest-filter=${filter}" + ] +} \ No newline at end of file diff --git a/build.zig b/build.zig index 369ac0a..ec2f5e5 100644 --- a/build.zig +++ b/build.zig @@ -34,7 +34,16 @@ pub fn build(b: *std.Build) void { } const exe_tests = b.addTest(.{ - .root_module = exe.root_module, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/tests.zig"), + .target = target, + .optimize = optimize, + + .imports = &.{ + .{ .name = "dvui", .module = dvui_dep.module("dvui_sdl3") }, + .{ .name = "sdl-backend", .module = dvui_dep.module("sdl3") }, + }, + }), }); const run_exe_tests = b.addRunArtifact(exe_tests); diff --git a/src/Canvas.zig b/src/Canvas.zig index 4be802a..c388bbb 100644 --- a/src/Canvas.zig +++ b/src/Canvas.zig @@ -1,18 +1,14 @@ const std = @import("std"); const builtin = @import("builtin"); const dvui = @import("dvui"); +const Document = @import("models/Document.zig"); +const RenderEngine = @import("render/RenderEngine.zig").RenderEngine; +const ImageRect = @import("models/rasterization_models.zig").ImageRect; const Size = dvui.Size; const Color = dvui.Color; const Canvas = @This(); -pub const ImageRect = struct { - x: u32, - y: u32, - w: u32, - h: u32, -}; - allocator: std.mem.Allocator, texture: ?dvui.Texture = null, size: Size = .{ .w = 800, .h = 600 }, @@ -24,11 +20,16 @@ scroll: dvui.ScrollInfo = .{ native_scaling: bool = false, gradient_start: Color.PMA = .{ .r = 0, .g = 0, .b = 0, .a = 255 }, gradient_end: Color.PMA = .{ .r = 255, .g = 255, .b = 255, .a = 255 }, +document: ?*Document = null, +render_engine: RenderEngine, _visible_rect: ?ImageRect = null, _zoom: f32 = 1, -pub fn init(allocator: std.mem.Allocator) Canvas { - return .{ .allocator = allocator }; +pub fn init(allocator: std.mem.Allocator, engine: RenderEngine) Canvas { + return .{ + .allocator = allocator, + .render_engine = engine, + }; } pub fn deinit(self: *Canvas) void { @@ -39,7 +40,7 @@ pub fn deinit(self: *Canvas) void { } /// Заполнить canvas градиентом -pub fn redrawGradient(self: *Canvas) !void { +pub fn redrawExample(self: *Canvas) !void { const full = self.getScaledImageSize(); const full_w: u32 = full.w; const full_h: u32 = full.h; @@ -57,10 +58,14 @@ pub fn redrawGradient(self: *Canvas) !void { const width: u32 = vis.w; const height: u32 = vis.h; + // 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; @@ -95,14 +100,15 @@ pub fn redrawGradient(self: *Canvas) !void { } /// Заполнить canvas случайным градиентом -pub fn fillRandomGradient(self: *Canvas) !void { +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 }; - try self.redrawGradient(); + self.render_engine.exampleReset(); + try self.redrawExample(); } pub fn setZoom(self: *Canvas, value: f32) void { @@ -136,7 +142,7 @@ pub fn updateVisibleImageRect(self: *Canvas, viewport: dvui.Rect, scroll_offset: } self._visible_rect = next; if (changed or self.texture == null) { - try self.redrawGradient(); + try self.redrawExample(); } } @@ -194,10 +200,3 @@ fn floatToClampedU32(value: f32, max_inclusive: u32) u32 { if (value >= max_f) return max_inclusive; return @intFromFloat(value); } - -/// Отобразить canvas в UI -pub fn render(self: Canvas, rect: dvui.RectScale) !void { - if (self.texture) |texture| { - try dvui.renderTexture(texture, rect, .{}); - } -} diff --git a/src/WindowContext.zig b/src/WindowContext.zig index af4757f..ff07de9 100644 --- a/src/WindowContext.zig +++ b/src/WindowContext.zig @@ -1,19 +1,27 @@ const std = @import("std"); -const dvui = @import("dvui"); const Canvas = @import("Canvas.zig"); +const CpuRenderEngine = @import("render/CpuRenderEngine.zig"); const WindowContext = @This(); allocator: std.mem.Allocator, canvas: Canvas, +cpu_render: *CpuRenderEngine, -pub fn init(allocator: std.mem.Allocator) WindowContext { - return .{ - .allocator = allocator, - .canvas = Canvas.init(allocator), - }; +pub fn init(allocator: std.mem.Allocator) !WindowContext { + var self: WindowContext = undefined; + self.allocator = allocator; + + self.cpu_render = try allocator.create(CpuRenderEngine); + errdefer allocator.destroy(self.cpu_render); + self.cpu_render.* = CpuRenderEngine.init(allocator, .Gradient); + + self.canvas = Canvas.init(allocator, self.cpu_render.renderEngine()); + + return self; } pub fn deinit(self: *WindowContext) void { self.canvas.deinit(); + self.allocator.destroy(self.cpu_render); } diff --git a/src/main.zig b/src/main.zig index 2cb006f..bd82ebd 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,9 +1,9 @@ const std = @import("std"); const builtin = @import("builtin"); const dvui = @import("dvui"); -const dvui_ext = @import("./ui/dvui_ext.zig"); +const dvui_ext = @import("ui/dvui_ext.zig"); const SDLBackend = @import("sdl-backend"); -const Document = @import("Document.zig"); +const Document = @import("models/Document.zig"); const WindowContext = @import("WindowContext.zig"); const sdl_c = SDLBackend.c; const Allocator = std.mem.Allocator; @@ -29,7 +29,7 @@ pub fn main() !void { }); defer win.deinit(); - var ctx = WindowContext.init(allocator); + var ctx = try WindowContext.init(allocator); defer ctx.deinit(); var interrupted = false; @@ -90,7 +90,7 @@ fn gui_frame(ctx: *WindowContext) bool { { dvui.label(@src(), "Tools", .{}, .{}); if (dvui.button(@src(), "Fill Random Color", .{}, .{})) { - canvas.fillRandomGradient() catch |err| { + canvas.exampleReset() catch |err| { std.debug.print("Error filling canvas: {}\n", .{err}); }; canvas.pos = .{ .x = 400, .y = 400 }; @@ -198,7 +198,7 @@ fn gui_frame(ctx: *WindowContext) bool { switch (action) { .wheel_y => |y| { canvas.addZoom(y / 1000); - canvas.redrawGradient() catch {}; + canvas.redrawExample() catch {}; }, else => {}, } diff --git a/src/Document.zig b/src/models/Document.zig similarity index 100% rename from src/Document.zig rename to src/models/Document.zig diff --git a/src/models/rasterization_models.zig b/src/models/rasterization_models.zig new file mode 100644 index 0000000..ba31ce5 --- /dev/null +++ b/src/models/rasterization_models.zig @@ -0,0 +1,11 @@ +pub const ImageRect = struct { + x: u32, + y: u32, + w: u32, + h: u32, +}; + +pub const ImageSize = struct { + w: u32, + h: u32, +}; diff --git a/src/render/CpuRenderEngine.zig b/src/render/CpuRenderEngine.zig new file mode 100644 index 0000000..ffa2120 --- /dev/null +++ b/src/render/CpuRenderEngine.zig @@ -0,0 +1,46 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const dvui = @import("dvui"); +const RenderEngine = @import("RenderEngine.zig").RenderEngine; +const rast_models = @import("../models/rasterization_models.zig"); +const ImageSize = rast_models.ImageSize; +const ImageRect = rast_models.ImageRect; +const Allocator = std.mem.Allocator; +const Color = dvui.Color; + +const CpuRenderEngine = @This(); +const Type = enum { + Gradient, + Squares, +}; + +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 }, + +pub fn init(allocator: Allocator, render_type: Type) CpuRenderEngine { + return .{ + ._allocator = allocator, + .type = render_type, + }; +} + +pub fn exampleReset(self: *CpuRenderEngine) 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 }; +} + +pub fn example(self: CpuRenderEngine, canvas_size: ImageSize, visible_rect: ImageRect) !?dvui.Texture { + _ = self; + _ = canvas_size; + _ = visible_rect; + return null; +} + +pub fn renderEngine(self: *CpuRenderEngine) RenderEngine { + return .{ .cpu = self }; +} diff --git a/src/render/IRenderEngine.zig b/src/render/IRenderEngine.zig deleted file mode 100644 index 2cf24d8..0000000 --- a/src/render/IRenderEngine.zig +++ /dev/null @@ -1 +0,0 @@ -// Интерфейс для рендеринга документа diff --git a/src/render/RenderEngine.zig b/src/render/RenderEngine.zig new file mode 100644 index 0000000..49829c1 --- /dev/null +++ b/src/render/RenderEngine.zig @@ -0,0 +1,20 @@ +// Интерфейс для рендеринга документа +const dvui = @import("dvui"); +const CpuRenderEngine = @import("CpuRenderEngine.zig"); +const rast_models = @import("../models/rasterization_models.zig"); + +pub const RenderEngine = union(enum) { + cpu: *CpuRenderEngine, + + pub fn exampleReset(self: RenderEngine) void { + switch (self) { + .cpu => |cpu_r| cpu_r.exampleReset(), + } + } + + pub fn example(self: RenderEngine, canvas_size: rast_models.ImageSize, visible_rect: rast_models.ImageRect) !?dvui.Texture { + return switch (self) { + .cpu => |cpu_r| cpu_r.example(canvas_size, visible_rect), + }; + } +}; diff --git a/src/tests.zig b/src/tests.zig new file mode 100644 index 0000000..29bfb5a --- /dev/null +++ b/src/tests.zig @@ -0,0 +1,6 @@ +// Test root for `zig build test`. +// Import modules here to ensure their `test` blocks are discovered. + +test "module test discovery" { + _ = @import("render/CpuRenderEngine.zig"); +}