DVUI

renderNinepatch

Renders a ninepatch with the given parameters.

Only valid between Window.beginand Window.end.

Parameters

#
ninepatch:Ninepatch
Ninepatch
rs:RectScale
RectScale
opts:NinepatchOptions
NinepatchOptions

Source

Implementation

#
pub fn renderNinepatch(ninepatch: Ninepatch, rs: RectScale, opts: NinepatchOptions) Backend.GenericError!void {
    if (ninepatch.source.imageFile.bytes.len == 0) return;
    if (rs.s == 0) return;
    if (rs.r.empty()) return;
    if (dvui.clipGet().intersect(rs.r).empty()) return;

    const tex = ninepatch.source.getTexture() catch |err| {
        dvui.log.err("renderNinepatch() got {any}", .{err});
        return;
    };

    var rect = rs.r;
    if (dvui.currentWindow().snap_to_pixels) {
        rect.x = @round(rect.x);
        rect.y = @round(rect.y);
    }

    const ts: Size = .{
        .w = @floatFromInt(tex.width),
        .h = @floatFromInt(tex.width),
    };

    // scale ninepatch edge size
    const e = ninepatch.edge.scale(rs.s, Rect.Physical);

    // middle
    var r = rect.inset(e);
    if (!r.empty()) {
        try renderTexture(tex, .{ .r = r, .s = rs.s }, .{
            .uv = .{
                .x = ninepatch.edge.x / ts.w,
                .w = (ts.w - ninepatch.edge.x - ninepatch.edge.w) / ts.w,
                .y = ninepatch.edge.y / ts.h,
                .h = (ts.h - ninepatch.edge.y - ninepatch.edge.h) / ts.h,
            },
            .debug = opts.debug,
        });
    }

    // top and bottom edges
    r = rect.inset(.{ .x = e.x, .w = e.w });
    if (!r.empty()) {
        // bottom first, draw as much as possible from bottom up
        var height = @min(r.h, e.h);
        const bottom = r.y + r.h;
        var th = height / rs.s;
        try renderTexture(tex, .{ .r = .{
            .x = r.x,
            .w = r.w,
            .y = bottom - height,
            .h = height,
        }, .s = rs.s }, .{
            .uv = .{
                .x = ninepatch.edge.x / ts.w,
                .w = (ts.w - ninepatch.edge.x - ninepatch.edge.w) / ts.w,
                .y = (ts.h - th) / ts.h,
                .h = th / ts.h,
            },
            .debug = opts.debug,
        });

        // top edge
        height = @min(r.h, e.y);
        th = height / rs.s;
        try renderTexture(tex, .{ .r = .{
            .x = r.x,
            .w = r.w,
            .y = r.y,
            .h = height,
        }, .s = rs.s }, .{
            .uv = .{
                .x = ninepatch.edge.x / ts.w,
                .w = (ts.w - ninepatch.edge.x - ninepatch.edge.w) / ts.w,
                .y = 0,
                .h = th / ts.h,
            },
            .debug = opts.debug,
        });
    }

    // left and right edges
    r = rect.inset(.{ .y = e.y, .h = e.h });
    if (!r.empty()) {
        // right first, draw from right edge
        var width = @min(r.w, e.w);
        const right = r.x + r.w;
        var tw = width / rs.s;
        try renderTexture(tex, .{ .r = .{
            .x = right - width,
            .w = width,
            .y = r.y,
            .h = r.h,
        }, .s = rs.s }, .{
            .uv = .{
                .x = (ts.w - tw) / ts.w,
                .w = tw / ts.w,
                .y = ninepatch.edge.y / ts.h,
                .h = (ts.h - ninepatch.edge.y - ninepatch.edge.h) / ts.h,
            },
            .debug = opts.debug,
        });

        // left
        width = @min(r.w, e.x);
        tw = width / rs.s;
        try renderTexture(tex, .{ .r = .{
            .x = r.x,
            .w = width,
            .y = r.y,
            .h = r.h,
        }, .s = rs.s }, .{
            .uv = .{
                .x = 0,
                .w = tw / ts.w,
                .y = ninepatch.edge.y / ts.h,
                .h = (ts.h - ninepatch.edge.y - ninepatch.edge.h) / ts.h,
            },
            .debug = opts.debug,
        });
    }

    // bottom right corner
    {
        r = rect;
        const width = @min(r.w, e.w);
        const tw = width / rs.s;
        const height = @min(r.h, e.h);
        const th = height / rs.s;
        if (!r.empty()) {
            try renderTexture(tex, .{ .r = .{
                .x = r.x + r.w - width,
                .w = width,
                .y = r.y + r.h - height,
                .h = height,
            }, .s = rs.s }, .{
                .uv = .{
                    .x = (ts.w - tw) / ts.w,
                    .w = tw / ts.w,
                    .y = (ts.h - th) / ts.h,
                    .h = th / ts.h,
                },
                .debug = opts.debug,
            });
        }
    }

    // bottom left corner
    {
        r = rect;
        const width = @min(r.w, e.x);
        const tw = width / rs.s;
        const height = @min(r.h, e.h);
        const th = height / rs.s;
        if (!r.empty()) {
            try renderTexture(tex, .{ .r = .{
                .x = r.x,
                .w = width,
                .y = r.y + r.h - height,
                .h = height,
            }, .s = rs.s }, .{
                .uv = .{
                    .x = 0,
                    .w = tw / ts.w,
                    .y = (ts.h - th) / ts.h,
                    .h = th / ts.h,
                },
                .debug = opts.debug,
            });
        }
    }

    // top right corner
    {
        r = rect;
        const width = @min(r.w, e.w);
        const tw = width / rs.s;
        const height = @min(r.h, e.y);
        const th = height / rs.s;
        if (!r.empty()) {
            try renderTexture(tex, .{ .r = .{
                .x = r.x + r.w - width,
                .w = width,
                .y = r.y,
                .h = height,
            }, .s = rs.s }, .{
                .uv = .{
                    .x = (ts.w - tw) / ts.w,
                    .w = tw / ts.w,
                    .y = 0,
                    .h = th / ts.h,
                },
                .debug = opts.debug,
            });
        }
    }

    // top left corner
    {
        r = rect;
        const width = @min(r.w, e.x);
        const tw = width / rs.s;
        const height = @min(r.h, e.y);
        const th = height / rs.s;
        if (!r.empty()) {
            try renderTexture(tex, .{ .r = .{
                .x = r.x,
                .w = width,
                .y = r.y,
                .h = height,
            }, .s = rs.s }, .{
                .uv = .{
                    .x = 0,
                    .w = tw / ts.w,
                    .y = 0,
                    .h = th / ts.h,
                },
                .debug = opts.debug,
            });
        }
    }
}