const std = @import("std"); const Document = @import("../../models/Document.zig"); const pipeline = @import("pipeline.zig"); const DrawContext = pipeline.DrawContext; const Color = @import("dvui").Color; const Object = Document.Object; const default_stroke: Color.PMA = .{ .r = 0, .g = 0, .b = 0, .a = 255 }; /// Рисует линию в локальных координатах: от (0,0) до end_point. Растеризация в координатах буфера (без пробелов при зуме). pub fn draw(ctx: *DrawContext, obj: *const Object) void { const ep_prop = obj.getProperty(.end_point) orelse return; const end_x = ep_prop.end_point.x; const end_y = ep_prop.end_point.y; const stroke = if (obj.getProperty(.stroke_rgba)) |s| pipeline.rgbaToPma(s.stroke_rgba) else default_stroke; drawLine(ctx, 0, 0, end_x, end_y, stroke); } /// Линия по локальным координатам фигуры: переводит концы в буфер и рисует в пикселях буфера. pub fn drawLine(ctx: *DrawContext, x0: f32, y0: f32, x1: f32, y1: f32, color: Color.PMA) void { const w0 = ctx.localToWorld(x0, y0); const w1 = ctx.localToWorld(x1, y1); const b0 = ctx.worldToBufferF(w0.x, w0.y); const b1 = ctx.worldToBufferF(w1.x, w1.y); const bx0: i32 = @intFromFloat(std.math.round(b0.x)); const by0: i32 = @intFromFloat(std.math.round(b0.y)); const bx1: i32 = @intFromFloat(std.math.round(b1.x)); const by1: i32 = @intFromFloat(std.math.round(b1.y)); drawLineInBuffer(ctx, bx0, by0, bx1, by1, color); } /// Брезенхем в координатах буфера; пиксели вне [0, buf_width) x [0, buf_height) пропускаются. pub fn drawLineInBuffer(ctx: *DrawContext, bx0: i32, by0: i32, bx1: i32, by1: i32, color: Color.PMA) void { const bw: i32 = @intCast(ctx.buf_width); const bh: i32 = @intCast(ctx.buf_height); const dx: i32 = @intCast(@abs(bx1 - bx0)); const dy: i32 = -@as(i32, @intCast(@abs(by1 - by0))); const sx: i32 = if (bx0 < bx1) 1 else -1; const sy: i32 = if (by0 < by1) 1 else -1; var err = dx + dy; var x = bx0; var y = by0; while (true) { if (x >= 0 and x < bw and y >= 0 and y < bh) { ctx.blendPixelAtBuffer(@intCast(x), @intCast(y), color); } if (x == bx1 and y == by1) break; const e2 = 2 * err; if (e2 >= dy) { err += dy; x += sx; } if (e2 <= dx) { err += dx; y += sy; } } }