From d79befe12a8d6b32a41beb88d6e75b12a75615a7 Mon Sep 17 00:00:00 2001 From: Tom Barrett Date: Wed, 30 Jun 2021 17:19:47 +0200 Subject: rotating cube --- .gitignore | 1 + build.zig | 21 +++++++++ src/main.zig | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/matrix.zig | 54 +++++++++++++++++++++++ src/sdl.zig | 95 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 304 insertions(+) create mode 100644 .gitignore create mode 100644 build.zig create mode 100644 src/main.zig create mode 100644 src/matrix.zig create mode 100644 src/sdl.zig 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, +}; -- cgit v1.2.3