From 32ec3cfdc080756ab02ee6ebf02408c4006a8b47 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Mon, 19 Feb 2024 22:49:44 +0100 Subject: [PATCH] feat: implement stencils --- build.zig.zon | 4 +-- src/Sdl2Painter.zig | 73 ++++++++++++++++++++++++++++++++++++-------- src/Sdl2Platform.zig | 6 +++- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 5ced5a0..74373d8 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,8 +9,8 @@ .dependencies = .{ .zenolith = .{ - .url = "git+https://git.mzte.de/zenolith/zenolith.git#6f318242d7bb5dad079e5ad6421900744e5d03b4", - .hash = "122034a7efb688149b6251c939407e31b1574de418c947a9b25478957d91aad69f5f", + .url = "git+https://git.mzte.de/zenolith/zenolith.git#431cd4adf7f141a83887a7c09375628d79d1962a", + .hash = "12206042c1f7851e8b1626d5b57b6054ac9f01a0476525823d34ab62f543e31aec23", }, .sdl2 = .{ diff --git a/src/Sdl2Painter.zig b/src/Sdl2Painter.zig index d50b766..6e18c43 100644 --- a/src/Sdl2Painter.zig +++ b/src/Sdl2Painter.zig @@ -13,9 +13,15 @@ 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, @@ -24,25 +30,54 @@ pub fn rect( color.a, ) != 0) return error.Render; - if (c.SDL_RenderFillRect(self.renderer, &util.toSdlRect(rectangle)) != 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(src), - &util.toSdlRect(dest), + &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 { @@ -57,18 +92,32 @@ pub fn span( if (c.SDL_SetTextureAlphaMod(font.atlas, 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, - &util.toSdlRect( - // This is sound as the span will have already gotten the glyph from the font, - // causing it to add it to the map. - font.getSprite(g.glyph.codepoint, zspan.style.size) orelse unreachable, - ), - &util.toSdlRect(.{ - .pos = pos.add(g.position), - .size = g.glyph.size, - }), + &util.toSdlRect(sprite_clip), + &util.toSdlRect(clip_rect), ) != 0) return error.Render; } } diff --git a/src/Sdl2Platform.zig b/src/Sdl2Platform.zig index bee86d4..f0efa48 100644 --- a/src/Sdl2Platform.zig +++ b/src/Sdl2Platform.zig @@ -290,7 +290,11 @@ pub fn run( if (c.SDL_SetRenderDrawColor(self.renderer, 0, 0, 0, 0xff) != 0) return error.Render; if (c.SDL_RenderClear(self.renderer) != 0) return error.Render; - var painter = zenolith.painter.Painter.create(Sdl2Painter{ .renderer = self.renderer }, {}); + var painter = zenolith.painter.Painter.create( + Sdl2Painter{ .renderer = self.renderer }, + zenolith.painter.PainterData.init(root.data.allocator), + ); + defer painter.data.deinit(); const current_time = std.time.nanoTimestamp(); try zenolith.treevent.fire(root, zenolith.treevent.Draw{ .painter = &painter,