Files
Zivro/src/render/cpu/line.zig

61 lines
2.5 KiB
Zig

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;
}
}
}