const std = @import("std"); const matrix = @import("matrix.zig"); const sdl = @import("sdl.zig"); const ArenaAllocator = std.heap.ArenaAllocator; const Cube = struct { points: [8]Point, }; pub const Point = struct { x: f32, y: f32, z: f32, }; pub fn draw_cube(instance: sdl.instance, cube: Cube) void { sdl.draw_color(instance, 255, 255, 255, 0); sdl.draw_line(instance, cube.points[0], cube.points[1]); sdl.draw_line(instance, cube.points[0], cube.points[2]); sdl.draw_line(instance, cube.points[0], cube.points[4]); sdl.draw_line(instance, cube.points[7], cube.points[6]); sdl.draw_line(instance, cube.points[7], cube.points[5]); sdl.draw_line(instance, cube.points[7], cube.points[3]); sdl.draw_line(instance, cube.points[2], cube.points[3]); sdl.draw_line(instance, cube.points[4], cube.points[5]); sdl.draw_line(instance, cube.points[1], cube.points[5]); sdl.draw_line(instance, cube.points[6], cube.points[2]); sdl.draw_line(instance, cube.points[3], cube.points[1]); sdl.draw_line(instance, cube.points[4], cube.points[6]); } pub fn shift_cube(cube: Cube, x: f32, y: f32, z: f32) Cube { var shifted_cube = Cube{ .points = undefined }; for (cube.points) |point, i| { shifted_cube.points[i].x = point.x + x; shifted_cube.points[i].y = point.y + y; shifted_cube.points[i].z = point.z + z; } return shifted_cube; } pub fn center_cube(cube: Cube, offset: f32) Cube { var centered_cube = Cube{ .points = undefined }; for (cube.points) |point, i| { centered_cube.points[i] = center_point(point, offset); } return centered_cube; } pub fn center_point(point: Point, offset: f32) Point { return Point{ .x = point.x + offset, .y = point.y + offset, .z = 0, }; } pub fn rotate_cube(arena: *ArenaAllocator, cube: Cube, alpha: f32, beta: f32) Cube { var rotated_cube = Cube{ .points = undefined }; for (cube.points) |point, i| { rotated_cube.points[i] = rotate_point(arena, point, alpha, beta); } return rotated_cube; } pub fn rotate_point(arena: *ArenaAllocator, point: Point, alpha: f32, beta: f32) Point { var a = matrix.new( arena, 3, 3, &[_]f32{ 1, 0, 0, 0, @cos(alpha), @sin(alpha), 0, -@sin(alpha), @cos(alpha), }, ); var b = matrix.new( arena, 3, 3, &[_]f32{ @cos(beta), 0, -@sin(beta), 0, 1, 0, @sin(beta), 0, @cos(beta), }, ); var m = matrix.multiply( arena, matrix.multiply(arena, a, b), matrix.new(arena, 3, 1, &[3]f32{ point.x, point.y, point.z }), ); return Point{ .x = m.x.items[0], .y = m.x.items[1], .z = m.x.items[2], }; } pub fn project_cube(arena: *ArenaAllocator, cube: Cube) Cube { var projected_cube = Cube{ .points = undefined }; for (cube.points) |point, i| { projected_cube.points[i] = project_point(arena, point); } return projected_cube; } pub fn project_point(arena: *ArenaAllocator, p: Point) Point { var cx = [_]f32{ 1, 0, 0, 0, 1, 0, 0, 0, 0, }; var c = matrix.new(arena, 3, 3, &cx); var m = matrix.multiply(arena, c, matrix.new(arena, 3, 1, &[3]f32{ p.x, p.y, p.z })); return Point{ .x = m.x.items[0], .y = m.x.items[1], .z = m.x.items[2], }; } pub fn scale_cube(cube: Cube, scale: f32) Cube { var scaled_cube = Cube{ .points = undefined }; for (cube.points) |point, i| { scaled_cube.points[i].x = point.x * scale; scaled_cube.points[i].y = point.y * scale; scaled_cube.points[i].z = point.z * scale; } return scaled_cube; } pub fn draw_axis(arena: *ArenaAllocator, instance: sdl.instance) void { var o = center_point( project_point(arena, Point{ .x = 0, .y = 0, .z = 0 }), 250, ); var x = center_point( project_point(arena, Point{ .x = 50, .y = 0, .z = 0 }), 250, ); var y = center_point( project_point(arena, Point{ .x = 0, .y = 50, .z = 0 }), 250, ); var z = center_point( project_point(arena, Point{ .x = 0, .y = 0, .z = 50 }), 250, ); sdl.draw_color(instance, 255, 0, 0, 0); sdl.draw_line(instance, o, x); sdl.draw_color(instance, 0, 255, 0, 0); sdl.draw_line(instance, o, y); sdl.draw_color(instance, 0, 0, 255, 0); sdl.draw_line(instance, o, z); } pub fn main() anyerror!void { var instance = sdl.init(); const unit_cube = Cube{ .points = [8]Point{ Point{ .x = 1, .y = 1, .z = 1 }, Point{ .x = 1, .y = 1, .z = -1 }, Point{ .x = 1, .y = -1, .z = 1 }, Point{ .x = 1, .y = -1, .z = -1 }, Point{ .x = -1, .y = 1, .z = 1 }, Point{ .x = -1, .y = 1, .z = -1 }, Point{ .x = -1, .y = -1, .z = 1 }, Point{ .x = -1, .y = -1, .z = -1 }, }, }; var beta: f32 = 0; var alpha: f32 = 0; while (true) { var arena = ArenaAllocator.init(std.heap.page_allocator); 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, } } sdl.draw_color(instance, 0, 0, 0, 0); sdl.clear(instance); draw_axis(&arena, instance); var cube = rotate_cube(&arena, unit_cube, alpha, beta); cube = scale_cube(cube, 50); cube = project_cube(&arena, cube); cube = center_cube(cube, 250); draw_cube(instance, cube); cube = rotate_cube(&arena, unit_cube, alpha + 90, beta + 90); cube = scale_cube(cube, 25); cube = project_cube(&arena, cube); cube = center_cube(cube, 250); draw_cube(instance, cube); cube = shift_cube(unit_cube, 5, 0, 0); cube = rotate_cube(&arena, cube, 2 * alpha, 2 * beta); cube = scale_cube(cube, 25); cube = project_cube(&arena, cube); cube = center_cube(cube, 250); draw_cube(instance, cube); cube = shift_cube(unit_cube, -5, 0, 0); cube = rotate_cube(&arena, cube, 2 * alpha, 2 * beta); cube = scale_cube(cube, 25); cube = project_cube(&arena, cube); cube = center_cube(cube, 250); draw_cube(instance, cube); beta += 0.01; alpha += 0.01; arena.deinit(); sdl.present(instance); sdl.delay(10); } sdl.quit(instance); }