ref: ccccea5a7cb177a440075a711c12272096c2bc77
parent: 21bd719e29393785e549018970ec95146ae8361b
author: Jacob G-W <[email protected]>
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: {