1
0
Fork 0
zenolith-sdl2/src/Sdl2Painter.zig
mcmrcs@proton.me 563e01c2f2 feat: implemented create and update texture (#2)
Reviewed-on: https://git.mzte.de/zenolith/zenolith-sdl2/pulls/2
Co-authored-by: mcmrcs@proton.me <marciusdasilva51@gmail.com>
Co-committed-by: mcmrcs@proton.me <marciusdasilva51@gmail.com>
2024-03-18 23:16:48 +01:00

124 lines
3.9 KiB
Zig

const std = @import("std");
const zenolith = @import("zenolith");
const util = @import("util.zig");
const c = @import("ffi.zig").c;
const Sdl2Font = @import("Sdl2Font.zig");
const Sdl2Texture = @import("Sdl2Texture.zig");
renderer: *c.SDL_Renderer,
const Sdl2Painter = @This();
pub fn rect(
self: *Sdl2Painter,
selfp: *zenolith.painter.Painter,
rectangle: zenolith.layout.Rectangle,
color: zenolith.Color,
) !void {
const clip_rect = if (selfp.data.peekStencil()) |stenc|
rectangle.intersection(stenc) orelse return
else
rectangle;
if (c.SDL_SetRenderDrawColor(
self.renderer,
color.r,
color.g,
color.b,
color.a,
) != 0) return error.Render;
if (c.SDL_RenderFillRect(self.renderer, &util.toSdlRect(clip_rect)) != 0) return error.Render;
}
pub fn texturedRect(
self: *Sdl2Painter,
selfp: *zenolith.painter.Painter,
src: zenolith.layout.Rectangle,
dest: zenolith.layout.Rectangle,
texture: *zenolith.texture.Texture,
) !void {
const clip_dest = if (selfp.data.peekStencil()) |stenc|
dest.intersection(stenc) orelse return
else
dest;
// TODO: this is simply inacceptable... but it works
const x_scale: f64 = @as(f64, @floatFromInt(clip_dest.size.width)) /
@as(f64, @floatFromInt(dest.size.width));
const y_scale: f64 = @as(f64, @floatFromInt(clip_dest.size.height)) /
@as(f64, @floatFromInt(dest.size.height));
const x_mv_scale: f64 = @as(f64, @floatFromInt(clip_dest.pos.x - dest.pos.x)) /
@as(f64, @floatFromInt(dest.size.width));
const y_mv_scale: f64 = @as(f64, @floatFromInt(clip_dest.pos.y - dest.pos.y)) /
@as(f64, @floatFromInt(dest.size.height));
const clip_src = zenolith.layout.Rectangle{
.pos = .{
.x = src.pos.x + @as(i32, @intFromFloat(@as(f64, @floatFromInt(src.size.width)) * x_mv_scale)),
.y = src.pos.y + @as(i32, @intFromFloat(@as(f64, @floatFromInt(src.size.height)) * y_mv_scale)),
},
.size = .{
.width = @intFromFloat(@as(f64, @floatFromInt(src.size.width)) * x_scale),
.height = @intFromFloat(@as(f64, @floatFromInt(src.size.height)) * y_scale),
},
};
if (c.SDL_RenderCopy(
self.renderer,
(texture.downcast(Sdl2Texture) orelse unreachable).tex,
&util.toSdlRect(clip_src),
&util.toSdlRect(clip_dest),
) != 0) return error.Render;
}
pub fn span(
self: *Sdl2Painter,
selfp: *zenolith.painter.Painter,
pos: zenolith.layout.Position,
zspan: zenolith.text.Span,
) !void {
const font = zspan.font.downcast(Sdl2Font) orelse unreachable;
if (c.SDL_SetTextureColorMod(
font.atlas.tex,
zspan.style.color.r,
zspan.style.color.g,
zspan.style.color.b,
) != 0) return error.Render;
if (c.SDL_SetTextureAlphaMod(font.atlas.tex, zspan.style.color.a) != 0) return error.Render;
for (zspan.glyphs.items) |g| {
// This is sound as the span will have already gotten the glyph from the font,
// causing it to add it to the map.
const sprite_rect = font.getSprite(g.glyph.codepoint, zspan.style.size) orelse unreachable;
const rectangle = zenolith.layout.Rectangle{
.pos = pos.add(g.position),
.size = g.glyph.size,
};
const clip_rect = if (selfp.data.peekStencil()) |stenc|
rectangle.intersection(stenc) orelse continue
else
rectangle;
std.debug.assert(std.meta.eql(sprite_rect.size, rectangle.size));
const sprite_clip = zenolith.layout.Rectangle{
.pos = sprite_rect.pos.add(clip_rect.pos.sub(rectangle.pos)),
.size = clip_rect.size,
};
if (c.SDL_RenderCopy(
self.renderer,
font.atlas.tex,
&util.toSdlRect(sprite_clip),
&util.toSdlRect(clip_rect),
) != 0) return error.Render;
}
}