shithub: libdraw-zig

Download patch

ref: e3c2fff3fead8501068149464c2716ed5f06a594
parent: ccccea5a7cb177a440075a711c12272096c2bc77
author: Jacob G-W <[email protected]>
date: Wed Jul 19 18:25:49 EDT 2023

add bouncing example

binary files /dev/null b/bouncing differ
--- a/build.sh
+++ b/build.sh
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash 
 # just a temporary fix until the x86_64 backend supports build.zig
-~/dev/zig/build/debug/bin/zig build-exe examples/main.zig --main-pkg-path . -target x86_64-plan9-none -freference-trace -fsingle-threaded --zig-lib-dir ~/dev/zig/lib
+~/dev/zig/build/debug/bin/zig build-exe "examples/$1.zig" --main-pkg-path . -target x86_64-plan9-none -freference-trace -fsingle-threaded --zig-lib-dir ~/dev/zig/lib
--- /dev/null
+++ b/examples/bouncing.zig
@@ -1,0 +1,53 @@
+const std = @import("std");
+const ld = @import("../src/libdraw.zig");
+const Point = ld.Point;
+const Rectangle = ld.Rectangle;
+var colors: [15]*ld.Image = undefined;
+const cs: [15]u32 = .{
+    0xff0000ff,
+    0xff3600ff,
+    0xff6d00ff,
+    0xffa400ff,
+    0xffda00ff,
+    0xdbff00ff,
+    0x6dff00ff,
+    0x00ff00ff,
+    0x00926dff,
+    0x0024dbff,
+    0x1500dbff,
+    0x3600a6ff,
+    0x540094ff,
+    0x7000c9ff,
+    0x8b00ffff,
+};
+pub fn main() !void {
+    const ally = std.heap.page_allocator;
+    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 {};
+    for (cs, &colors) |c, *color| {
+        color.* = try d.allocImage(Rectangle.init(0, 0, 1, 1), .rgba32, true, c);
+    }
+    var frames: usize = 0;
+    const screen = d.getScreen();
+    var ball: ld.Point = .{ .x = @divFloor((screen.r.max.x + screen.r.min.x), 2), .y = screen.r.max.y };
+    var vel: ld.Point = .{ .x = 2, .y = -1 };
+    while (true) {
+        frames += 1;
+        try screen.draw(screen.r, d.white, null, ld.Point.Zero);
+        try screen.ellipse(ball, 8, 8, 8, colors[@divFloor(frames, 30) % 15], ld.Point.Zero);
+        ball.x += vel.x;
+        ball.y += vel.y;
+        vel.y += 2;
+        if (ball.y > screen.r.max.y) {
+            vel.y *= -1;
+        }
+        if (ball.x < screen.r.min.x or ball.x > screen.r.max.x) {
+            vel.x *= -1;
+        }
+        try d.flushImage(true);
+        _ = std.os.plan9.syscall_bits.syscall1(.SLEEP, 20);
+    }
+}
--- a/examples/main.zig
+++ b/examples/main.zig
@@ -1,7 +1,86 @@
 const std = @import("std");
 const ld = @import("../src/libdraw.zig");
 const SQUARELEN = 40;
-const SPACING = 10;
+const SPACING = 15;
+const Point = ld.Point;
+const Rectangle = ld.Rectangle;
+const Ball = struct {
+    const FPoint = struct {
+        x: f32,
+        y: f32,
+        fn toPoint(self: @This()) Point {
+            return .{ .x = @intFromFloat(self.x), .y = @intFromFloat(self.y) };
+        }
+    };
+    pos: FPoint,
+    vel: FPoint,
+    fn collide(b: *Ball) void {
+        var i: u16 = 0;
+        while (i < numbricks_vert) : (i += 1) {
+            var j: u16 = 0;
+            while (j < numbricks_horiz) : (j += 1) {
+                const val = bricks[i * numbricks_vert + j];
+                if (val == 0) continue;
+                switch (b.testCollide(i, j)) {
+                    .horiz => {
+                        bricks[i * numbricks_vert + j] -|= 1;
+                        b.vel.y *= -1;
+                        return;
+                    },
+                    .vert => {
+                        bricks[i * numbricks_vert + j] -|= 1;
+                        b.vel.x *= -1;
+                        return;
+                    },
+                    .none => {},
+                }
+            }
+        }
+    }
+    fn testCollide(self: Ball, i: u16, j: u16) enum { horiz, vert, none } {
+        const brick = getBrickRect(i, j);
+        const p = self.pos.toPoint();
+        const brickcenter: Point = .{ .x = brick.min.x + @divFloor(brick.width(), 2), .y = @divFloor(brick.min.y + brick.height(), 2) };
+        if (p.x >= brick.min.x and
+            p.x <= brick.max.x and
+            p.y >= brick.min.y and
+            p.y <= brick.max.y)
+        {
+            // const a = std.math.radiansToDegrees(f32, std.math.atan2(f32, @as(f32, @floatFromInt(brickcenter.y - p.y)), @as(f32, @floatFromInt(brickcenter.x - p.x))));
+            // if (@fabs(a) < 45 or @fabs(a) >= 135) return .horiz;
+            // return .vert;
+            if (std.math.absInt(p.x - brickcenter.x) catch unreachable < std.math.absInt(p.y - brickcenter.y) catch unreachable) return .vert;
+            return .horiz;
+        }
+        return .none;
+    }
+};
+var bricks: []u32 = undefined;
+var screenr: ld.Rectangle = undefined;
+var balls: std.ArrayList(Ball) = undefined;
+var numbricks_vert: u32 = undefined;
+var numbricks_horiz: u32 = undefined;
+var colors: [15]*ld.Image = undefined;
+const cs: [15]u32 = .{
+    0xff0000ff,
+    0xff3600ff,
+    0xff6d00ff,
+    0xffa400ff,
+    0xffda00ff,
+    0xdbff00ff,
+    0x6dff00ff,
+    0x00ff00ff,
+    0x00926dff,
+    0x0024dbff,
+    0x1500dbff,
+    0x3600a6ff,
+    0x540094ff,
+    0x7000c9ff,
+    0x8b00ffff,
+};
+fn getBrickRect(i: u16, j: u16) Rectangle {
+    return 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);
+}
 pub fn main() !void {
     const ally = std.heap.page_allocator;
     const d = ld.initDraw(ally, null, "balls") catch |e| {
@@ -12,37 +91,57 @@
     const screen = d.getScreen();
     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;
+    for (cs, &colors) |c, *color| {
+        color.* = try d.allocImage(Rectangle.init(0, 0, 1, 1), .rgba32, true, c);
     }
-    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 };
+    screenr = screen.r;
+    numbricks_horiz = @intCast(@divFloor(width, SQUARELEN));
+    numbricks_vert = @intCast(@divFloor(height, SQUARELEN) - 3);
+    bricks = try ally.alloc(u32, numbricks_horiz * numbricks_vert);
+    for (bricks) |*square| {
+        square.* = 14;
+    }
+    balls = try std.ArrayList(Ball).initCapacity(ally, 40);
+    // var angle: f32 = std.math.degreesToRadians(f32, 80);
+    // try balls.append(.{ .pos = .{ .x = @divFloor(screenr.min.x + screenr.max.x, 2), .y = screenr.max.y }, .vel = .{ .x = @cos(angle), .y = @sin(angle) } });
+    try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = 3.4, .y = 2.8 } });
+    try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = 1.4, .y = 7.8 } });
+    try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = 0.4, .y = 8.8 } });
+    try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = -4.1, .y = 0.5 } });
     while (true) {
-        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;
+        // clear the screen
+        try screen.draw(screen.r, d.white, null, Point.Zero);
+        // collide the balls
+        // update the balls
+        for (balls.items) |*ball| {
+            ball.collide();
+            ball.pos.x += ball.vel.x;
+            ball.pos.y += ball.vel.y;
+            const p = ball.pos.toPoint();
+            if (p.x > screenr.max.x or p.x < screenr.min.x) {
+                ball.vel.x *= -1;
+            }
+            if (p.y > screenr.max.y or p.y < screenr.min.y) {
+                ball.vel.y *= -1;
+            }
         }
-        if (ball.y > screenr.max.y or ball.y < screenr.min.y) {
-            ballv.y *= -1;
-        }
+        var quit = true;
+        // draw the squares
         var i: u16 = 0;
-        while (i < numsquares_vert) : (i += 1) {
+        while (i < numbricks_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);
+            while (j < numbricks_horiz) : (j += 1) {
+                const square = bricks[i * numbricks_vert + j];
+                if (square > 0) {
+                    quit = false;
+                    try screen.draw(getBrickRect(i, j), colors[square], null, Point.Zero);
+                }
             }
         }
-        try screen.ellipse(ball, 10, 10, 10, d.black, ld.Point.Zero);
+        if (quit) break;
+        for (balls.items) |ball| {
+            try screen.ellipse(ball.pos.toPoint(), 3, 3, 3, d.black, Point.Zero);
+        }
         try d.flushImage(true);
         _ = std.os.plan9.syscall_bits.syscall1(.SLEEP, 10);
     }
--- a/src/libdraw.zig
+++ b/src/libdraw.zig
@@ -221,10 +221,10 @@
         }
         return true;
     }
-    pub fn dX(self: Rectangle) i64 {
+    pub fn dX(self: Rectangle) i32 {
         return self.max.x - self.min.x;
     }
-    pub fn dY(self: Rectangle) i64 {
+    pub fn dY(self: Rectangle) i32 {
         return self.max.y - self.min.y;
     }
     pub const width = dX;