const std = @import("std"); const Document = @import("../../models/Document.zig"); const pipeline = @import("pipeline.zig"); const line = @import("line.zig"); const ellipse = @import("ellipse.zig"); const broken = @import("broken.zig"); const arc = @import("arc.zig"); const basic_models = @import("../../models/basic_models.zig"); const Rect_i = basic_models.Rect_i; const Size_i = basic_models.Size_i; const Object = Document.Object; const DrawContext = pipeline.DrawContext; const Transform = pipeline.Transform; fn isVisible(obj: *const Object) bool { return if (obj.getProperty(.visible)) |p| p.visible else true; } fn drawObject( ctx: *DrawContext, obj: *const Object, parent_transform: Transform, allocator: std.mem.Allocator, ) !void { if (!isVisible(obj)) return; const local = Transform.init(obj); const world = Transform.compose(parent_transform, local); ctx.setTransform(world); switch (obj.shape) { .line => line.draw(ctx, obj), .ellipse => ellipse.draw(ctx, obj), .broken => try broken.draw(ctx, obj, allocator), .arc => arc.draw(ctx, obj), } for (obj.children.items) |*child| { try drawObject(ctx, child, world, allocator); } } /// Рекурсивно рисует документ в буфер (объекты и потомки по порядку). /// allocator опционален; если передан, ломаные рисуются через слой (без двойного наложения при alpha < 1). pub fn drawDocument( pixels: []@import("dvui").Color.PMA, buf_width: u32, buf_height: u32, visible_rect: Rect_i, document: *const Document, canvas_size: Size_i, allocator: std.mem.Allocator, ) !void { const scale_x: f32 = if (document.size.w > 0) @as(f32, @floatFromInt(canvas_size.w)) / document.size.w else 0; const scale_y: f32 = if (document.size.h > 0) @as(f32, @floatFromInt(canvas_size.h)) / document.size.h else 0; var ctx = DrawContext{ .pixels = pixels, .buf_width = buf_width, .buf_height = buf_height, .visible_rect = visible_rect, .scale_x = scale_x, .scale_y = scale_y, }; const identity = Transform{}; for (document.objects.items) |*obj| { try drawObject(&ctx, obj, identity, allocator); } }