const sdl = @import("./sdl.zig").c; const std = @import("std"); const GameState = @import("./game_state.zig").GameState; const Offset = @import("./utils/offset.zig").Offset; const RGBAColor = @import("./utils/rgb_color.zig").RGBAColor; const FONT_SIZE = 24; var font: ?*sdl.TTF_Font = null; var text_init = false; pub const GameTextFactoryController = struct { texts: std.ArrayList(GameText), pub fn init(allocator: std.mem.Allocator) !GameTextFactoryController { try initFont(); return .{ .texts = std.ArrayList(GameText).init(allocator), }; } fn initFont() !void { const loaded_font = sdl.TTF_OpenFont("./assets/fonts/DepartureMonoNF-Regular.ttf", FONT_SIZE) orelse { sdl.SDL_Log("Error loading ttf font: %s\n", sdl.TTF_GetError()); return error.FailedToLoadFont; }; font = loaded_font; text_init = true; } pub fn deinit(self: *GameTextFactoryController) void { self.texts.deinit(); deinitFont(); } fn deinitFont() void { sdl.TTF_CloseFont(font); text_init = false; } pub fn addText(self: *GameTextFactoryController, text_ctx: GameTextContext) !void { try self.texts.append(GameText.initFromContext(text_ctx)); } pub fn render(self: *GameTextFactoryController, renderer: *sdl.SDL_Renderer, game_state: *const GameState) !void { _ = game_state; for (self.texts.items) |text| { const c_text: [*c]const u8 = @ptrCast(text.text); // TODO dont create new surface if unchanged const text_surface: [*c]sdl.SDL_Surface = sdl.TTF_RenderText_Solid(font.?, c_text, text.color) orelse { sdl.SDL_Log("Error loading text surface: %s\n", sdl.SDL_GetError()); return error.FailedToRenderSurface; }; defer sdl.SDL_FreeSurface(text_surface); if (!text_init) { return error.TextNotInitialized; } // TODO dont create new texture if unchanged const text_texture = sdl.SDL_CreateTextureFromSurface(renderer, text_surface) orelse { sdl.SDL_Log("Error loading text texture: %s\n", sdl.SDL_GetError()); return error.FailedToRenderTexture; }; defer sdl.SDL_DestroyTexture(text_texture); const w: c_int = @intCast(text_surface.*.w); const h: c_int = @intCast(text_surface.*.h); const srcr = sdl.SDL_Rect{ .x = 0, .y = 0, .w = w, .h = h }; const destr = sdl.SDL_Rect{ .x = @intCast(text.offset.x), .y = @intCast(text.offset.y), .w = w, .h = h }; _ = sdl.SDL_RenderCopy(renderer, text_texture, &srcr, &destr); } } pub fn spawnFactory(self: *GameTextFactoryController, allocator: std.mem.Allocator) void { const texts = self.texts.items; var texts_copy = try allocator.alloc(GameText, texts.len); errdefer allocator.free(texts_copy); std.mem.copyForwards(GameText, texts_copy, texts); return .{ .texts = &texts_copy, }; } }; pub const GameTextFactory = struct { texts: []GameText, text_surfaces: [*c]sdl.SDL_Surface, }; pub const GameTextContext = struct { text: [*:0]const u8, color: sdl.SDL_Color = RGBAColor.whiteSmoke().tosdl(), // TODO Constraints?? offset: Offset = .{ .x = 0, .y = 0 }, }; pub const GameText = struct { text: [*:0]const u8, color: sdl.SDL_Color, offset: Offset, // pub fn deinit(self: *GameText) void { // sdl.SDL_FreeSurface(self.text_surface); // } pub fn setBlendMode(self: *GameText, blend: sdl.SDL_BlendMode) !void { _ = self; _ = blend; return error.Unimplemented; } pub fn setAlpha(self: *GameText, alpha: u8) !void { _ = self; _ = alpha; return error.Unimplemented; } pub fn initFromContext(ctx: GameTextContext) GameText { return .{ .text = ctx.text, .color = ctx.color, .offset = ctx.offset, }; } };