summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Barrett <tom@tombarrett.xyz>2021-06-30 17:19:47 +0200
committerTom Barrett <tom@tombarrett.xyz>2021-06-30 17:19:47 +0200
commitd79befe12a8d6b32a41beb88d6e75b12a75615a7 (patch)
tree365aa28165efa3e4727ce5ea0edbdf6c69135952
rotating cube
-rw-r--r--.gitignore1
-rw-r--r--build.zig21
-rw-r--r--src/main.zig133
-rw-r--r--src/matrix.zig54
-rw-r--r--src/sdl.zig95
5 files changed, 304 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..faeaecd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+zig*
diff --git a/build.zig b/build.zig
new file mode 100644
index 0000000..bbd4531
--- /dev/null
+++ b/build.zig
@@ -0,0 +1,21 @@
+const std = @import("std");
+
+pub fn build(b: *std.build.Builder) void {
+ const target = b.standardTargetOptions(.{});
+ const mode = b.standardReleaseOptions();
+
+ const exe = b.addExecutable("cube", "src/main.zig");
+ exe.setTarget(target);
+ exe.setBuildMode(mode);
+ exe.install();
+ exe.linkSystemLibrary("SDL2");
+
+ const run_cmd = exe.run();
+ run_cmd.step.dependOn(b.getInstallStep());
+ if (b.args) |args| {
+ run_cmd.addArgs(args);
+ }
+
+ const run_step = b.step("run", "Run the app");
+ run_step.dependOn(&run_cmd.step);
+}
diff --git a/src/main.zig b/src/main.zig
new file mode 100644
index 0000000..909e4ae
--- /dev/null
+++ b/src/main.zig
@@ -0,0 +1,133 @@
+const std = @import("std");
+const matrix = @import("matrix.zig");
+const sdl = @import("sdl.zig");
+
+const Cube = struct {
+ points: [8][3]f32,
+};
+
+pub fn draw_cube(instance: sdl.instance, cube: Cube) void {
+ sdl.draw_color(instance, 0, 0, 0, 0);
+ sdl.clear(instance);
+
+ var c = cube.points;
+ sdl.draw_color(instance, 255, 255, 255, 0);
+ sdl.draw_line(instance, &c[0], &c[1]);
+ sdl.draw_line(instance, &c[0], &c[2]);
+ sdl.draw_line(instance, &c[0], &c[4]);
+
+ sdl.draw_line(instance, &c[7], &c[6]);
+ sdl.draw_line(instance, &c[7], &c[5]);
+ sdl.draw_line(instance, &c[7], &c[3]);
+
+ sdl.draw_line(instance, &c[2], &c[3]);
+ sdl.draw_line(instance, &c[4], &c[5]);
+ sdl.draw_line(instance, &c[1], &c[5]);
+
+ sdl.draw_line(instance, &c[6], &c[2]);
+ sdl.draw_line(instance, &c[3], &c[1]);
+ sdl.draw_line(instance, &c[4], &c[6]);
+
+ sdl.present(instance);
+}
+
+pub fn get_centered_cube(cube: Cube, offset: f32) Cube {
+ var centered_cube = Cube{ .points = undefined };
+ for (cube.points) |point, i| {
+ for (point) |dimension, j| {
+ centered_cube.points[i][j] = dimension + offset;
+ }
+ }
+ return centered_cube;
+}
+
+pub fn get_projected_cube(cube: Cube, alpha: f32, beta: f32) Cube {
+ var projected_cube = Cube{ .points = undefined };
+
+ var ax = [_]f32{
+ 1, 0, 0,
+ 0, @cos(alpha), @sin(alpha),
+ 0, -@sin(alpha), @cos(alpha),
+ };
+ var a = matrix.new(3, 3, &ax);
+
+ var bx = [_]f32{
+ @cos(beta), 0, -@sin(beta),
+ 0, 1, 0,
+ @sin(beta), 0, @cos(beta),
+ };
+ var b = matrix.new(3, 3, &bx);
+
+ var cx = [_]f32{
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 0,
+ };
+ var c = matrix.new(3, 3, &cx);
+
+ for (cube.points) |point, i| {
+ var p = point;
+ var x = matrix.multiply(c, matrix.multiply(matrix.multiply(a, b), matrix.new(3, 1, &p))).x.items;
+ projected_cube.points[i][0] = x[0];
+ projected_cube.points[i][1] = x[1];
+ }
+
+ return projected_cube;
+}
+
+pub fn get_scaled_cube(cube: Cube, scale: f32) Cube {
+ var scaled_cube = Cube{ .points = undefined };
+ for (cube.points) |point, i| {
+ for (point) |dimension, j| {
+ scaled_cube.points[i][j] = dimension * scale;
+ }
+ }
+ return scaled_cube;
+}
+
+pub fn main() anyerror!void {
+ var instance = sdl.init();
+
+ const unit_cube = Cube{
+ .points = [8][3]f32{
+ [3]f32{ 01, 01, 01 },
+ [3]f32{ 01, 01, -1 },
+ [3]f32{ 01, -1, 01 },
+ [3]f32{ 01, -1, -1 },
+ [3]f32{ -1, 01, 01 },
+ [3]f32{ -1, 01, -1 },
+ [3]f32{ -1, -1, 01 },
+ [3]f32{ -1, -1, -1 },
+ },
+ };
+
+ var counter: u32 = 0;
+ var beta: f32 = 0;
+ var alpha: f32 = 35.264;
+ while (true) {
+ var event = sdl.get_event();
+ if (event.mode == sdl.modes.quit) {
+ break;
+ } else if (event.mode == sdl.modes.key) {
+ switch (event.key) {
+ sdl.keys.q => break,
+ else => continue,
+ }
+ }
+
+ var cube = get_projected_cube(unit_cube, alpha, beta);
+ cube = get_scaled_cube(cube, 100);
+ cube = get_centered_cube(cube, 250);
+ draw_cube(instance, cube);
+ beta += 0.01;
+ alpha += 0.01;
+
+ sdl.delay(10);
+ counter += 10;
+ if (counter > 10000) {
+ break;
+ }
+ }
+
+ sdl.quit(instance);
+}
diff --git a/src/matrix.zig b/src/matrix.zig
new file mode 100644
index 0000000..eaf9685
--- /dev/null
+++ b/src/matrix.zig
@@ -0,0 +1,54 @@
+const std = @import("std");
+const ArrayList = std.ArrayList;
+
+const matrix = struct {
+ h: usize,
+ w: usize,
+ x: ArrayList(f32),
+};
+
+pub fn new(h: usize, w: usize, x: []f32) matrix {
+ var m = matrix{
+ .h = h,
+ .w = w,
+ .x = ArrayList(f32).init(std.heap.page_allocator),
+ };
+
+ var i: usize = 0;
+ while (i < h * w) : (i += 1) {
+ if (m.x.append(x[i])) |val| {} else |err| {}
+ }
+
+ return m;
+}
+
+pub fn dot(a: []f32, b: []f32, len: usize, step: usize) f32 {
+ var x: f32 = 0;
+ var j: usize = 0;
+ var i: usize = len;
+ var k: usize = 0;
+
+ while (i > 0) : (i -= 1) {
+ x += a[k] * b[j];
+ k += 1;
+ j += step;
+ }
+
+ return x;
+}
+
+pub fn multiply(a: matrix, b: matrix) matrix {
+ var x = ArrayList(f32).init(std.heap.page_allocator);
+ var i: usize = 0;
+ var k: usize = 0;
+
+ while (i < a.h) : (i += 1) {
+ var j: usize = 0;
+ while (j < b.w) : (j += 1) {
+ if (x.append(dot(a.x.items[k..], b.x.items[j..], a.w, b.w))) |val| {} else |err| {}
+ }
+ k += a.w;
+ }
+
+ return new(a.h, b.w, x.items);
+}
diff --git a/src/sdl.zig b/src/sdl.zig
new file mode 100644
index 0000000..d9828af
--- /dev/null
+++ b/src/sdl.zig
@@ -0,0 +1,95 @@
+const std = @import("std");
+const sdl = @cImport(@cInclude("SDL2/SDL.h"));
+
+pub const instance = struct {
+ renderer: ?*sdl.SDL_Renderer,
+ window: ?*sdl.SDL_Window,
+};
+
+pub fn init() instance {
+ _ = sdl.SDL_Init(sdl.SDL_INIT_VIDEO);
+ var window = sdl.SDL_CreateWindow(
+ "main",
+ sdl.SDL_WINDOWPOS_UNDEFINED,
+ sdl.SDL_WINDOWPOS_UNDEFINED,
+ 500,
+ 500,
+ sdl.SDL_WINDOW_SHOWN,
+ );
+
+ var renderer = sdl.SDL_CreateRenderer(
+ window,
+ -1,
+ sdl.SDL_RENDERER_ACCELERATED,
+ );
+
+ return instance{
+ .window = window,
+ .renderer = renderer,
+ };
+}
+
+pub fn draw_line(i: instance, p1: []f32, p2: []f32) void {
+ _ = sdl.SDL_RenderDrawLineF(i.renderer, p1[0], p1[1], p2[0], p2[1]);
+}
+
+pub fn delay(t: u32) void {
+ sdl.SDL_Delay(t);
+}
+
+pub fn draw_color(i: instance, r: u8, g: u8, b: u8, a: u8) void {
+ _ = sdl.SDL_SetRenderDrawColor(i.renderer, r, g, b, a);
+}
+
+pub fn clear(i: instance) void {
+ _ = sdl.SDL_RenderClear(i.renderer);
+}
+
+pub fn present(i: instance) void {
+ sdl.SDL_RenderPresent(i.renderer);
+}
+
+pub fn get_event() event {
+ var e: sdl.SDL_Event = undefined;
+ _ = sdl.SDL_PollEvent(&e);
+
+ var key = keys.none;
+ var mode = modes.mouse;
+ //var key = @intToEnum(keys, e.key.keysym.sym);
+ //var mode = @intToEnum(modes, e.type);
+
+ var r: event = event{
+ .key = key,
+ .mode = mode,
+ };
+ return r;
+}
+
+const event = struct {
+ key: keys,
+ mode: modes,
+};
+
+pub const modes = enum(u32) {
+ mouse = sdl.SDL_MOUSEMOTION,
+ window = sdl.SDL_WINDOWEVENT,
+ quit = sdl.SDL_QUIT,
+ key = sdl.SDL_KEYDOWN,
+};
+
+pub fn quit(i: instance) void {
+ sdl.SDL_DestroyRenderer(i.renderer);
+ sdl.SDL_DestroyWindow(i.window);
+ sdl.SDL_Quit();
+}
+
+pub const keys = enum(i32) {
+ none = sdl.SDLK_UNKNOWN,
+ w = sdl.SDLK_w,
+ s = sdl.SDLK_s,
+ q = sdl.SDLK_q,
+ up = sdl.SDLK_UP,
+ down = sdl.SDLK_DOWN,
+ left = sdl.SDLK_LEFT,
+ right = sdl.SDLK_RIGHT,
+};