From 563e01c2f2211063bd968aea59d31af3fbb260aa Mon Sep 17 00:00:00 2001 From: "mcmrcs@proton.me" Date: Mon, 18 Mar 2024 23:16:48 +0100 Subject: [PATCH] feat: implemented create and update texture (#2) Reviewed-on: https://git.mzte.de/zenolith/zenolith-sdl2/pulls/2 Co-authored-by: mcmrcs@proton.me Co-committed-by: mcmrcs@proton.me --- src/Sdl2Font.zig | 16 ++++------ src/Sdl2Painter.zig | 6 ++-- src/Sdl2Platform.zig | 36 ++++++++++++++++------ src/Sdl2Texture.zig | 72 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 23 deletions(-) diff --git a/src/Sdl2Font.zig b/src/Sdl2Font.zig index ad54c07..8ab273d 100644 --- a/src/Sdl2Font.zig +++ b/src/Sdl2Font.zig @@ -7,8 +7,10 @@ const util = @import("util.zig"); const ffi = @import("ffi.zig"); const c = ffi.c; +const Sdl2Texture = @import("Sdl2Texture.zig"); + face: c.FT_Face, -atlas: *c.SDL_Texture, +atlas: Sdl2Texture, renderer: *c.SDL_Renderer, /// This is an ArrayHashMap to speed up iteration which is requried for collision checking. @@ -30,7 +32,7 @@ pub const GlyphProperties = struct { }; pub fn deinit(self: *Sdl2Font) void { - c.SDL_DestroyTexture(self.atlas); + self.atlas.deinit(); _ = c.FT_Done_Face(self.face); self.glyphs.deinit(); self.pixel_buf.deinit(); @@ -89,7 +91,7 @@ fn getSize(self: *Sdl2Font) zenolith.layout.Size { var h: c_int = 0; // This will only error if I messed up somewhere. - if (c.SDL_QueryTexture(self.atlas, null, null, &w, &h) != 0) unreachable; + if (c.SDL_QueryTexture(self.atlas.tex, null, null, &w, &h) != 0) unreachable; return .{ .width = @intCast(w), .height = @intCast(h) }; } @@ -158,13 +160,7 @@ pub fn addAtlastSprite(self: *Sdl2Font, data: []const u8, width: u31) !zenolith. }, }; - const rec = util.toSdlRect(rect); - if (c.SDL_UpdateTexture( - self.atlas, - &rec, - self.pixel_buf.items.ptr, - @intCast(width * 4), - ) != 0) return error.UpdateTexture; + try self.atlas.setPixels(self.pixel_buf.items, @intCast(width * 4), rect); return rect; } diff --git a/src/Sdl2Painter.zig b/src/Sdl2Painter.zig index 6e18c43..6b1b918 100644 --- a/src/Sdl2Painter.zig +++ b/src/Sdl2Painter.zig @@ -84,12 +84,12 @@ pub fn span( const font = zspan.font.downcast(Sdl2Font) orelse unreachable; if (c.SDL_SetTextureColorMod( - font.atlas, + 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, zspan.style.color.a) != 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, @@ -115,7 +115,7 @@ pub fn span( if (c.SDL_RenderCopy( self.renderer, - font.atlas, + font.atlas.tex, &util.toSdlRect(sprite_clip), &util.toSdlRect(clip_rect), ) != 0) return error.Render; diff --git a/src/Sdl2Platform.zig b/src/Sdl2Platform.zig index f0efa48..88ec3bc 100644 --- a/src/Sdl2Platform.zig +++ b/src/Sdl2Platform.zig @@ -342,7 +342,7 @@ pub const CreateFontOptions = struct { atlas_size: zenolith.layout.Size = .{ .width = 512, .height = 1024 }, }; -pub const CreateFontError = ffi.FreeTypeError || error{CreateTexture}; +pub const CreateFontError = ffi.FreeTypeError || error{ CreateTexture, SetBlendMode }; pub fn createFont(self: Sdl2Platform, opts: CreateFontOptions) CreateFontError!Sdl2Font { var face: c.FT_Face = undefined; @@ -363,16 +363,13 @@ pub fn createFont(self: Sdl2Platform, opts: CreateFontOptions) CreateFontError!S } errdefer _ = c.FT_Done_Face(face); - const atlas = c.SDL_CreateTexture( - self.renderer, - c.SDL_PIXELFORMAT_RGBA8888, - c.SDL_TEXTUREACCESS_STATIC, - @intCast(opts.atlas_size.width), - @intCast(opts.atlas_size.height), - ) orelse return error.CreateTexture; - errdefer c.SDL_DestroyTexture(atlas); + const atlas = try self.createTexture(.{ + .size = opts.atlas_size, + .pixel_format = .RGBA8888, + .pixel_access = .static, + }); - if (c.SDL_SetTextureBlendMode(atlas, c.SDL_BLENDMODE_BLEND) != 0) return error.CreateTexture; + try atlas.setBlendMode(.blend); return .{ .face = face, @@ -400,3 +397,22 @@ pub fn relayoutRoot(self: *Sdl2Platform, root: *zenolith.widget.Widget) !void { .position = .{ .x = 0, .y = 0 }, }); } +const CreateTextureOptions = struct { + size: zenolith.layout.Size, + pixel_format: Sdl2Texture.PixelFormat, + pixel_access: Sdl2Texture.PixelAccess = .static, +}; + +pub fn createTexture(self: Sdl2Platform, options: CreateTextureOptions) !Texture { + const texture = c.SDL_CreateTexture( + self.renderer, + @intFromEnum(options.pixel_format), + @intFromEnum(options.pixel_access), + options.size.width, + options.size.height, + ) orelse return error.CreateTexture; + + return Texture{ + .tex = texture, + }; +} diff --git a/src/Sdl2Texture.zig b/src/Sdl2Texture.zig index 8ebfd72..0c71ef2 100644 --- a/src/Sdl2Texture.zig +++ b/src/Sdl2Texture.zig @@ -3,6 +3,7 @@ const std = @import("std"); const zenolith = @import("zenolith"); const c = @import("ffi.zig").c; +const util = @import("util.zig"); const log = std.log.scoped(.zenolith_sdl2); @@ -10,6 +11,62 @@ tex: *c.SDL_Texture, const Sdl2Texture = @This(); +/// 32-bit integer formats have been removed, as they're assigned their `8888` equivalents +/// depending on system endianness. Directly use those instead. +pub const PixelFormat = enum(u32) { + INDEX1LSB = c.SDL_PIXELFORMAT_INDEX1LSB, + INDEX1MSB = c.SDL_PIXELFORMAT_INDEX1MSB, + INDEX4LSB = c.SDL_PIXELFORMAT_INDEX4LSB, + INDEX4MSB = c.SDL_PIXELFORMAT_INDEX4MSB, + INDEX8 = c.SDL_PIXELFORMAT_INDEX8, + RGB332 = c.SDL_PIXELFORMAT_RGB332, + RGB444 = c.SDL_PIXELFORMAT_RGB444, + RGB555 = c.SDL_PIXELFORMAT_RGB555, + BGR555 = c.SDL_PIXELFORMAT_BGR555, + ARGB4444 = c.SDL_PIXELFORMAT_ARGB4444, + RGBA4444 = c.SDL_PIXELFORMAT_RGBA4444, + ABGR4444 = c.SDL_PIXELFORMAT_ABGR4444, + BGRA4444 = c.SDL_PIXELFORMAT_BGRA4444, + ARGB1555 = c.SDL_PIXELFORMAT_ARGB1555, + RGBA5551 = c.SDL_PIXELFORMAT_RGBA5551, + ABGR1555 = c.SDL_PIXELFORMAT_ABGR1555, + BGRA5551 = c.SDL_PIXELFORMAT_BGRA5551, + RGB565 = c.SDL_PIXELFORMAT_RGB565, + BGR565 = c.SDL_PIXELFORMAT_BGR565, + RGB24 = c.SDL_PIXELFORMAT_RGB24, + BGR24 = c.SDL_PIXELFORMAT_BGR24, + RGB888 = c.SDL_PIXELFORMAT_RGB888, + RGBX8888 = c.SDL_PIXELFORMAT_RGBX8888, + BGR888 = c.SDL_PIXELFORMAT_BGR888, + BGRX8888 = c.SDL_PIXELFORMAT_BGRX8888, + ARGB8888 = c.SDL_PIXELFORMAT_ARGB8888, + RGBA8888 = c.SDL_PIXELFORMAT_RGBA8888, + ABGR8888 = c.SDL_PIXELFORMAT_ABGR8888, + BGRA8888 = c.SDL_PIXELFORMAT_BGRA8888, + ARGB2101010 = c.SDL_PIXELFORMAT_ARGB2101010, + YV12 = c.SDL_PIXELFORMAT_YV12, + IYUV = c.SDL_PIXELFORMAT_IYUV, + YUY2 = c.SDL_PIXELFORMAT_YUY2, + UYVY = c.SDL_PIXELFORMAT_UYVY, + YVYU = c.SDL_PIXELFORMAT_YVYU, + NV12 = c.SDL_PIXELFORMAT_NV12, + NV21 = c.SDL_PIXELFORMAT_NV21, +}; + +pub const PixelAccess = enum(c_int) { + static = c.SDL_TEXTUREACCESS_STATIC, + streaming = c.SDL_TEXTUREACCESS_STREAMING, + target = c.SDL_TEXTUREACCESS_TARGET, +}; + +pub const TextureBlendMode = enum(c_uint) { + none = c.SDL_BLENDMODE_NONE, + blend = c.SDL_BLENDMODE_BLEND, + add = c.SDL_BLENDMODE_ADD, + mod = c.SDL_BLENDMODE_MOD, + mul = c.SDL_BLENDMODE_MUL, +}; + pub fn getSize(self: Sdl2Texture) zenolith.layout.Size { var w: c_int = 0; var h: c_int = 0; @@ -21,3 +78,18 @@ pub fn getSize(self: Sdl2Texture) zenolith.layout.Size { return .{ .width = @intCast(w), .height = @intCast(h) }; } + +pub fn setPixels(self: Sdl2Texture, pixels: []const u8, pitch: u31, rect: ?zenolith.layout.Rectangle) !void { + std.debug.assert(pixels.len % pitch == 0); + + const rec = if (rect) |r| &util.toSdlRect(r) else null; + if (c.SDL_UpdateTexture(self.tex, rec, pixels.ptr, pitch) != 0) return error.UpdateTexture; +} + +pub fn setBlendMode(self: Sdl2Texture, blend_mode: TextureBlendMode) !void { + if (c.SDL_SetTextureBlendMode(self.tex, @intFromEnum(blend_mode)) != 0) return error.SetBlendMode; +} + +pub fn deinit(self: Sdl2Texture) void { + c.SDL_DestroyTexture(self.tex); +}