shithub: libdraw-zig

Download patch

ref: ccccea5a7cb177a440075a711c12272096c2bc77
parent: 21bd719e29393785e549018970ec95146ae8361b
author: Jacob G-W <jacoblevgw@gmail.com>
date: Mon Jul 17 07:50:51 EDT 2023

ellipses and bouncing ball

--- a/examples/main.zig
+++ b/examples/main.zig
@@ -1,48 +1,49 @@
 const std = @import("std");
 const ld = @import("../src/libdraw.zig");
+const SQUARELEN = 40;
+const SPACING = 10;
 pub fn main() !void {
     const ally = std.heap.page_allocator;
-    const d = ld.initDraw(ally, null, "rainbow") catch |e| {
+    const d = ld.initDraw(ally, null, "balls") catch |e| {
         std.debug.print("errstr: {s}\n", .{std.os.plan9.errstr()});
         return e;
     };
+    defer d.close() catch {};
     const screen = d.getScreen();
-    const colors = [_]u32{
-        ld.Color.Black,
-        ld.Color.White,
-        ld.Color.Red,
-        ld.Color.Green,
-        ld.Color.Blue,
-        ld.Color.Cyan,
-        ld.Color.Magenta,
-        ld.Color.Yellow,
-        ld.Color.Paleyellow,
-        ld.Color.Darkyellow,
-        ld.Color.Darkgreen,
-        ld.Color.Palegreen,
-        ld.Color.Medgreen,
-        ld.Color.Darkblue,
-        ld.Color.Palebluegreen,
-        ld.Color.Paleblue,
-        ld.Color.Bluegreen,
-        ld.Color.Greygreen,
-        ld.Color.Palegreygreen,
-        ld.Color.Yellowgreen,
-        ld.Color.Medblue,
-        ld.Color.Greyblue,
-        ld.Color.Palegreyblue,
-        ld.Color.Purpleblue,
-    };
-    var images: [colors.len]*ld.Image = undefined;
-    for (colors, 0..) |color, i| {
-        images[i] = try d.allocImage(ld.Rectangle.init(0, 0, 1, 1), ld.Chan.rgb24, true, color);
-        try d.flushImage(true);
+    const width = screen.r.width();
+    const height = screen.r.height();
+    const numsquares_horiz: u32 = @intCast(@divFloor(width, SQUARELEN));
+    const numsquares_vert: u32 = @intCast(@divFloor(height, SQUARELEN) - 3);
+    var squares = try ally.alloc(u32, numsquares_horiz * numsquares_vert);
+    for (squares) |*square| {
+        square.* = 10;
     }
+    const screenr = screen.r;
+    try d.flushImage(true);
+    var ball: ld.Point = .{ .x = @divFloor(screenr.min.x + screenr.max.x, 2), .y = screenr.max.y };
+    var ballv: ld.Point = .{ .x = 1, .y = -1 };
     while (true) {
-        for (images) |image| {
-            try screen.draw(screen.r, image, null, ld.Point.Zero);
-            try d.flushImage(true);
-            _ = std.os.plan9.syscall_bits.syscall1(.SLEEP, 750);
+        try screen.draw(screen.r, d.white, null, ld.Point.Zero);
+        ball.x += ballv.x;
+        ball.y += ballv.y;
+        if (ball.x > screenr.max.x or ball.x < screenr.min.x) {
+            ballv.x *= -1;
         }
+        if (ball.y > screenr.max.y or ball.y < screenr.min.y) {
+            ballv.y *= -1;
+        }
+        var i: u16 = 0;
+        while (i < numsquares_vert) : (i += 1) {
+            var j: u16 = 0;
+            while (j < numsquares_horiz) : (j += 1) {
+                const square = squares[i * numsquares_vert + j];
+                _ = square;
+                var rect = ld.Rectangle.init(screenr.min.x + SQUARELEN * j, screenr.min.y + SQUARELEN * i, screenr.min.x + SQUARELEN * (j + 1) - SPACING, screenr.min.y + SQUARELEN * (i + 1) - SPACING);
+                try screen.draw(rect, d.black, null, ld.Point.Zero);
+            }
+        }
+        try screen.ellipse(ball, 10, 10, 10, d.black, ld.Point.Zero);
+        try d.flushImage(true);
+        _ = std.os.plan9.syscall_bits.syscall1(.SLEEP, 10);
     }
 }
--- a/src/libdraw.zig
+++ b/src/libdraw.zig
@@ -1,12 +1,5 @@
 const std = @import("std");
 
-pub fn parseIntSkipPreceedingSpaces(comptime T: type, buf: []const u8) !T {
-    var i: u32 = 0;
-    while (buf[i] == ' ') i += 1;
-    const int = try std.fmt.parseInt(T, buf[i..], 10);
-    return int;
-}
-
 pub const Image = struct {
     display: *Display, // display holding data
     id: u32, // id of system-held Image
@@ -105,6 +98,60 @@
     pub fn gendrawop(dst: *Image, r: Rectangle, src: ?*Image, p0: Point, mask: ?*Image, p1: Point, op: DrawOp) !void {
         return draw1(dst, r, src, p0, mask, p1, op);
     }
+
+    pub fn doellipse(dst: *Image, cmd: u8, c: Point, xr: u32, yr: u32, thick: u32, src: *Image, sp: Point, alpha: u32, phi: u32, op: DrawOp) !void {
+        try dst.display.setDrawOp(op);
+
+        const a = try dst.display.allocBuf(1 + 4 + 4 + 2 * 4 + 4 + 4 + 4 + 2 * 4 + 2 * 4);
+        a.writeByte(cmd) catch unreachable;
+        a.writeIntLittle(u32, dst.id) catch unreachable;
+        a.writeIntLittle(u32, src.id) catch unreachable;
+        a.writeIntLittle(i32, c.x) catch unreachable;
+        a.writeIntLittle(i32, c.y) catch unreachable;
+        a.writeIntLittle(u32, xr) catch unreachable;
+        a.writeIntLittle(u32, yr) catch unreachable;
+        a.writeIntLittle(u32, thick) catch unreachable;
+        a.writeIntLittle(i32, sp.x) catch unreachable;
+        a.writeIntLittle(i32, sp.y) catch unreachable;
+        a.writeIntLittle(u32, alpha) catch unreachable;
+        a.writeIntLittle(u32, phi) catch unreachable;
+    }
+
+    pub fn ellipse(dst: *Image, c: Point, a: u32, b: u32, thick: u32, src: *Image, sp: Point) !void {
+        try dst.doellipse('e', c, a, b, thick, src, sp, 0, 0, .soverD);
+    }
+
+    pub fn ellipseop(dst: *Image, c: Point, a: u32, b: u32, thick: u32, src: *Image, sp: Point, op: DrawOp) !void {
+        try dst.doellipse('e', c, a, b, thick, src, sp, 0, 0, op);
+    }
+
+    pub fn fillellipse(dst: *Image, c: Point, a: u32, b: u32, src: *Image, sp: Point) !void {
+        try dst.doellipse('E', c, a, b, 0, src, sp, 0, 0, .soverD);
+    }
+
+    pub fn fillellipseop(dst: *Image, c: Point, a: u32, b: u32, src: *Image, sp: Point, op: DrawOp) !void {
+        try dst.doellipse('E', c, a, b, 0, src, sp, 0, 0, op);
+    }
+
+    pub fn arc(dst: *Image, c: Point, a: u32, b: u32, thick: u32, src: *Image, sp: Point, alpha: u32, phi: u32) !void {
+        const al = alpha | 1 << 31;
+        try dst.doellipse('e', c, a, b, thick, src, sp, al, phi, .soverD);
+    }
+
+    pub fn arcop(dst: *Image, c: Point, a: u32, b: u32, thick: u32, src: *Image, sp: Point, alpha: u32, phi: u32, op: DrawOp) !void {
+        const al = alpha | 1 << 31;
+        try dst.doellipse('e', c, a, b, thick, src, sp, al, phi, op);
+    }
+
+    pub fn fillarc(dst: *Image, c: Point, a: u32, b: u32, src: *Image, sp: Point, alpha: u32, phi: u32) !void {
+        const al = alpha | 1 << 31;
+        try dst.doellipse('E', c, a, b, 0, src, sp, al, phi, .soverD);
+    }
+
+    pub fn fillarcop(dst: *Image, c: Point, a: u32, b: u32, src: *Image, sp: *Image, alpha: u32, phi: u32, op: DrawOp) !void {
+        const al = alpha | 1 << 31;
+        try dst.doellipse('E', c, a, b, 0, src, sp, al, phi, op);
+    }
 };
 /// Porter-Duff compositing operators
 const DrawOp = enum(u8) {
@@ -180,6 +227,8 @@
     pub fn dY(self: Rectangle) i64 {
         return self.max.y - self.min.y;
     }
+    pub const width = dX;
+    pub const height = dY;
     pub fn inset(self: Rectangle, n: i32) Rectangle {
         var r = self;
         r.min.x += n;
@@ -231,7 +280,14 @@
     screen: ?*Image = null,
     _screen: ?*Screen = null,
     abpos: usize = 0, // for use in the writer
-    pub fn init(ally: std.mem.Allocator, options: struct { devdir: []const u8 = "/dev", windir: []const u8 = "/dev" }) !*Display {
+    pub fn parseIntSkipPreceedingSpaces(comptime T: type, buf: []const u8) !T {
+        var i: u32 = 0;
+        while (buf[i] == ' ') i += 1;
+        const int = try std.fmt.parseInt(T, buf[i..], 10);
+        return int;
+    }
+
+    pub fn open(ally: std.mem.Allocator, options: struct { devdir: []const u8 = "/dev", windir: []const u8 = "/dev" }) !*Display {
         const NINFO = 12 * 12;
         var info: [NINFO + 1]u8 = undefined;
         var buf: [512]u8 = undefined;
@@ -289,7 +345,6 @@
                 .next = null,
             };
         }
-        // TODO refactor this into a disp.* = .{ ... } expression
         const bufsize_iounit = iounit(datafd);
         const bufsz = if (bufsize_iounit == 0) 8000 else if (disp.bufsize < 512) return error.IounitTooSmall else bufsize_iounit;
         disp.* = .{
@@ -325,7 +380,9 @@
         errdefer ally.free(disp.buf);
         disp.bufp = disp.buf.ptr;
         disp.white = try disp.allocImage(Rectangle.init(0, 0, 1, 1), .grey1, true, Color.White);
+        errdefer disp.white.free() catch {};
         disp.black = try disp.allocImage(Rectangle.init(0, 0, 1, 1), .grey1, true, Color.Black);
+        errdefer disp.black.free() catch {};
         // disp.error = error;
         disp.windir = try ally.dupe(u8, options.windir);
         errdefer ally.free(disp.windir);
@@ -336,6 +393,17 @@
         disp.transparent = disp.black;
         return disp;
     }
+    pub fn close(self: *Display) !void {
+        // TODO reset the window's label to the old label
+        self.ally.free(self.devdir);
+        self.ally.free(self.windir);
+        try self.white.free();
+        try self.black.free();
+        self.fd.close();
+        self.ctlfd.close();
+        self.reffd.close();
+        self.ally.destroy(self);
+    }
     pub fn allocImage(self: *Display, r: Rectangle, chan: Chan, repl: bool, col: u32) !*Image {
         return self._allocImage(null, r, chan, repl, col, 0, .backup);
     }
@@ -784,7 +852,7 @@
 }
 pub fn genInitDraw(ally: std.mem.Allocator, devdir: []const u8, fontname: ?[]const u8, label: ?[]const u8, windir: []const u8, ref: Refresh) !*Display {
     var buf: [128]u8 = undefined;
-    var display = try Display.init(ally, .{ .devdir = devdir, .windir = windir });
+    var display = try Display.open(ally, .{ .devdir = devdir, .windir = windir });
     // TODO deal with fonts
     _ = fontname;
     if (label) |l| blk: {