diff --git a/build.zig b/build.zig index a1fd37a..7762c70 100644 --- a/build.zig +++ b/build.zig @@ -9,7 +9,6 @@ pub fn build(b: *std.Build) void { const use_llvm = b.option(bool, "use_llvm", "Enable llvm backend (default: none)"); const pie = b.option(bool, "pie", "Produce an executable with position independent code (default: none)"); const gui = b.option(bool, "gui", "Standalone GUI mode") orelse false; - const d2d = if (gui) b.option(bool, "d2d", "use the Direct2D backend (instead of Direct3D11)") orelse false else false; const run_step = b.step("run", "Run the app"); const check_step = b.step("check", "Check the app"); @@ -28,7 +27,6 @@ pub fn build(b: *std.Build) void { use_llvm, pie, gui, - d2d, ); } @@ -44,7 +42,6 @@ fn build_development( use_llvm: ?bool, pie: ?bool, gui: bool, - d2d: bool, ) void { const target = b.standardTargetOptions(.{ .default_target = .{ .abi = if (builtin.os.tag == .linux and !tracy_enabled) .musl else null } }); const optimize = b.standardOptimizeOption(.{}); @@ -64,7 +61,6 @@ fn build_development( use_llvm, pie, gui, - d2d, ); } @@ -80,7 +76,6 @@ fn build_release( use_llvm: ?bool, pie: ?bool, _: bool, //gui - d2d: bool, ) void { const targets: []const std.Target.Query = &.{ .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl }, @@ -123,7 +118,6 @@ fn build_release( use_llvm, pie, false, //gui - false, //d2d ); if (t.os_tag == .windows) @@ -142,7 +136,6 @@ fn build_release( use_llvm, pie, true, //gui - d2d, ); } } @@ -162,14 +155,12 @@ pub fn build_exe( use_llvm: ?bool, pie: ?bool, gui: bool, - d2d: bool, ) void { const options = b.addOptions(); options.addOption(bool, "enable_tracy", tracy_enabled); options.addOption(bool, "use_tree_sitter", use_tree_sitter); options.addOption(bool, "strip", strip); options.addOption(bool, "gui", gui); - options.addOption(bool, "d2d", d2d); const options_mod = options.createModule(); diff --git a/src/win32/d2d.zig b/src/win32/d2d.zig deleted file mode 100644 index e0b49b1..0000000 --- a/src/win32/d2d.zig +++ /dev/null @@ -1,250 +0,0 @@ -const std = @import("std"); -const win32 = @import("win32").everything; -const win32ext = @import("win32ext.zig"); -const ddui = @import("ddui"); -const vaxis = @import("vaxis"); -const dwrite = @import("dwrite.zig"); - -const RGB = @import("color").RGB; -const xterm = @import("xterm.zig"); -const XY = @import("xy.zig").XY; - -pub const Font = dwrite.Font; - -pub const NOREDIRECTIONBITMAP = 0; - -const global = struct { - var init_called: bool = false; - var d2d_factory: *win32.ID2D1Factory = undefined; - var background: win32.D2D_COLOR_F = .{ .r = 0.075, .g = 0.075, .b = 0.075, .a = 1.0 }; -}; - -pub fn init() void { - std.debug.assert(!global.init_called); - global.init_called = true; - dwrite.init(); - { - const hr = win32.D2D1CreateFactory( - .SINGLE_THREADED, - win32.IID_ID2D1Factory, - null, - @ptrCast(&global.d2d_factory), - ); - if (hr < 0) fatalHr("D2D1CreateFactory", hr); - } -} - -pub fn setBackground(state: *const WindowState, rgb: RGB) void { - _ = state; - global.background = ddui.rgb8(rgb.r, rgb.g, rgb.b); -} - -pub const WindowState = struct { - maybe_d2d: ?D2d = null, - pub fn init(hwnd: win32.HWND) WindowState { - _ = hwnd; - return .{}; - } -}; - -const D2d = struct { - target: *win32.ID2D1HwndRenderTarget, - brush: *win32.ID2D1SolidColorBrush, - pub fn init(hwnd: win32.HWND, err: *ddui.HResultError) error{HResult}!D2d { - var target: *win32.ID2D1HwndRenderTarget = undefined; - const target_props = win32.D2D1_RENDER_TARGET_PROPERTIES{ - .type = .DEFAULT, - .pixelFormat = .{ - .format = .B8G8R8A8_UNORM, - .alphaMode = .PREMULTIPLIED, - }, - .dpiX = 0, - .dpiY = 0, - .usage = .{}, - .minLevel = .DEFAULT, - }; - const hwnd_target_props = win32.D2D1_HWND_RENDER_TARGET_PROPERTIES{ - .hwnd = hwnd, - .pixelSize = .{ .width = 0, .height = 0 }, - .presentOptions = .{}, - }; - - { - const hr = global.d2d_factory.CreateHwndRenderTarget( - &target_props, - &hwnd_target_props, - &target, - ); - if (hr < 0) return err.set(hr, "CreateHwndRenderTarget"); - } - errdefer _ = target.IUnknown.Release(); - - { - const dc = win32ext.queryInterface(target, win32.ID2D1DeviceContext); - defer _ = dc.IUnknown.Release(); - // just make everything DPI aware, all applications should just do this - dc.SetUnitMode(win32.D2D1_UNIT_MODE_PIXELS); - } - - var brush: *win32.ID2D1SolidColorBrush = undefined; - { - const color: win32.D2D_COLOR_F = .{ .r = 0, .g = 0, .b = 0, .a = 0 }; - const hr = target.ID2D1RenderTarget.CreateSolidColorBrush(&color, null, &brush); - if (hr < 0) return err.set(hr, "CreateSolidBrush"); - } - errdefer _ = brush.IUnknown.Release(); - - return .{ - .target = target, - .brush = brush, - }; - } - pub fn deinit(self: *D2d) void { - _ = self.brush.IUnknown.Release(); - _ = self.target.IUnknown.Release(); - } - pub fn solid(self: *const D2d, color: win32.D2D_COLOR_F) *win32.ID2D1Brush { - self.brush.SetColor(&color); - return &self.brush.ID2D1Brush; - } -}; - -pub fn paint( - hwnd: win32.HWND, - state: *WindowState, - font: Font, - screen: *const vaxis.Screen, -) void { - const client_size = getClientSize(hwnd); - - const err: ddui.HResultError = blk: { - var ps: win32.PAINTSTRUCT = undefined; - _ = win32.BeginPaint(hwnd, &ps) orelse return fatalWin32( - "BeginPaint", - win32.GetLastError(), - ); - defer if (0 == win32.EndPaint(hwnd, &ps)) fatalWin32( - "EndPaint", - win32.GetLastError(), - ); - - if (state.maybe_d2d == null) { - var err: ddui.HResultError = undefined; - state.maybe_d2d = D2d.init(hwnd, &err) catch break :blk err; - } - - { - const size: win32.D2D_SIZE_U = .{ - .width = @intCast(client_size.x), - .height = @intCast(client_size.y), - }; - const hr = state.maybe_d2d.?.target.Resize(&size); - if (hr < 0) break :blk ddui.HResultError{ .context = "D2dResize", .hr = hr }; - } - - state.maybe_d2d.?.target.ID2D1RenderTarget.BeginDraw(); - paintD2d(&state.maybe_d2d.?, screen, font); - break :blk ddui.HResultError{ - .context = "D2dEndDraw", - .hr = state.maybe_d2d.?.target.ID2D1RenderTarget.EndDraw(null, null), - }; - }; - - if (err.hr == win32.D2DERR_RECREATE_TARGET) { - std.log.debug("D2DERR_RECREATE_TARGET", .{}); - state.maybe_d2d.?.deinit(); - state.maybe_d2d = null; - win32.invalidateHwnd(hwnd); - } else if (err.hr < 0) std.debug.panic("paint error: {}", .{err}); -} - -fn paintD2d( - d2d: *const D2d, - screen: *const vaxis.Screen, - font: Font, -) void { - d2d.target.ID2D1RenderTarget.Clear(&global.background); - for (0..screen.height) |y| { - const row_y: i32 = font.cell_size.y * @as(i32, @intCast(y)); - for (0..screen.width) |x| { - const column_x: i32 = font.cell_size.x * @as(i32, @intCast(x)); - const cell_index = screen.width * y + x; - const cell = &screen.buf[cell_index]; - - const cell_rect: win32.RECT = .{ - .left = column_x, - .top = row_y, - .right = column_x + font.cell_size.x, - .bottom = row_y + font.cell_size.y, - }; - ddui.FillRectangle( - &d2d.target.ID2D1RenderTarget, - cell_rect, - d2d.solid(d2dColorFromVAxis(cell.style.bg)), - ); - - // TODO: pre-caclulate the buffer size needed, for now this should just - // cause out-of-bounds access - var buf_wtf16: [100]u16 = undefined; - const grapheme_len = blk: { - break :blk std.unicode.wtf8ToWtf16Le(&buf_wtf16, cell.char.grapheme) catch |err| switch (err) { - error.InvalidWtf8 => { - buf_wtf16[0] = std.unicode.replacement_character; - break :blk 1; - }, - }; - }; - const grapheme = buf_wtf16[0..grapheme_len]; - if (std.mem.eql(u16, grapheme, &[_]u16{' '})) - continue; - ddui.DrawText( - &d2d.target.ID2D1RenderTarget, - grapheme, - font.text_format, - ddui.rectFloatFromInt(cell_rect), - d2d.solid(d2dColorFromVAxis(cell.style.fg)), - .{ - .CLIP = 1, - .ENABLE_COLOR_FONT = 1, - }, - .NATURAL, - ); - } - } -} - -fn d2dColorFromVAxis(color: vaxis.Cell.Color) win32.D2D_COLOR_F { - return switch (color) { - .default => .{ .r = 0, .g = 0, .b = 0, .a = 0 }, - .index => |idx| blk: { - const rgb = RGB.from_u24(xterm.colors[idx]); - break :blk .{ - .r = @as(f32, @floatFromInt(rgb.r)) / 255.0, - .g = @as(f32, @floatFromInt(rgb.g)) / 255.0, - .b = @as(f32, @floatFromInt(rgb.b)) / 255.0, - .a = 1, - }; - }, - .rgb => |rgb| .{ - .r = @as(f32, @floatFromInt(rgb[0])) / 255.0, - .g = @as(f32, @floatFromInt(rgb[1])) / 255.0, - .b = @as(f32, @floatFromInt(rgb[2])) / 255.0, - .a = 1, - }, - }; -} - -fn getClientSize(hwnd: win32.HWND) XY(i32) { - var rect: win32.RECT = undefined; - if (0 == win32.GetClientRect(hwnd, &rect)) - fatalWin32("GetClientRect", win32.GetLastError()); - std.debug.assert(rect.left == 0); - std.debug.assert(rect.top == 0); - return .{ .x = rect.right, .y = rect.bottom }; -} -fn fatalWin32(what: []const u8, err: win32.WIN32_ERROR) noreturn { - std.debug.panic("{s} failed with {}", .{ what, err.fmt() }); -} -fn fatalHr(what: []const u8, hresult: win32.HRESULT) noreturn { - std.debug.panic("{s} failed, hresult=0x{x}", .{ what, @as(u32, @bitCast(hresult)) }); -} diff --git a/src/win32/gui.zig b/src/win32/gui.zig index 82255ed..bc9091a 100644 --- a/src/win32/gui.zig +++ b/src/win32/gui.zig @@ -18,7 +18,7 @@ const RGB = @import("color").RGB; const input = @import("input"); const windowmsg = @import("windowmsg.zig"); -const render = if (build_options.d2d) @import("d2d.zig") else @import("d3d11.zig"); +const render = @import("d3d11.zig"); const FontFace = @import("FontFace.zig"); const XY = @import("xy.zig").XY;