Advertisement
Hadlock

cube.rs copilot generated 3d interactive scene

Jan 17th, 2024 (edited)
1,518
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 14.92 KB | Source Code | 0 0
  1. /*
  2. # cube.rs
  3.  
  4. this should draw a 2d representation of a wireframe cube hovering over a green ~~field~~ square which can be moved
  5.  
  6. i wrote this entirely with github copilot to see how far I could push it. no code was written by a human I just kept selecting the entire codebase and asking it to add specific functionality
  7.  
  8. cube:
  9.  
  10. - w/s forward/back
  11. - a/d left/right
  12. - q/e up/down
  13.  
  14. cube translation:
  15.  
  16. - i/k pitch
  17. - u/o yaw
  18. - j/l roll
  19.  
  20. camera:
  21.  
  22. - arrow keys up/down/left/right
  23. - ,/. pan left/right
  24.  
  25. I suggest using ,/. (< / > keys ) over the left/right keys.
  26.  
  27. ## suggestions
  28.  
  29. 1. when starting, press the `,` key to pan so you are directly in front of the cube (blue side facing away)
  30. 1. push `w` key to move the cube slightly away from the camera
  31. 1. use jkli/u/o keys to translate cube
  32.  
  33. ## building
  34.  
  35. 1. run `cargo new cube_rs`
  36. 1. add `minifb = "0.25.0"` to cargo.toml
  37. 1. copy-paste this file over `main.rs` in the ./src folder
  38. 1. run `cargo run`
  39.  
  40. ## notes
  41.  
  42. 1. runs at 240fps, mostly in an attempt to fix flicker
  43. 1. esc key to exit
  44. */
  45. use minifb::{Key, Window, WindowOptions};
  46. use std::time::{Duration, Instant};
  47. const WIDTH: usize = 800;
  48. const HEIGHT: usize = 600;
  49. const FRAME_RATE: u64 = 240;
  50.  
  51. fn main() {
  52.     // Create a window with blue background
  53.     let mut window = Window::new(
  54.         "3D Wireframe Cube",
  55.         WIDTH,
  56.         HEIGHT,
  57.         WindowOptions {
  58.             resize: true,
  59.             scale: minifb::Scale::X1,
  60.             ..Default::default()
  61.         },
  62.     )
  63.     .unwrap_or_else(|e| {
  64.         panic!("{}", e);
  65.     });
  66.     window.set_background_color(0xFF, 0xFF, 0xFF);
  67.  
  68.     // Cube vertices, edges, and initial positions
  69.     let mut vertices = [
  70.         [-1.0, -1.0, -1.0],
  71.         [1.0, -1.0, -1.0],
  72.         [1.0, 1.0, -1.0],
  73.         [-1.0, 1.0, -1.0],
  74.         [-1.0, -1.0, 1.0],
  75.         [1.0, -1.0, 1.0],
  76.         [1.0, 1.0, 1.0],
  77.         [-1.0, 1.0, 1.0],
  78.     ];
  79.  
  80.     // Cube edges
  81.     let edges = [
  82.         (0, 1),
  83.         (1, 2),
  84.         (2, 3),
  85.         (3, 0),
  86.         (4, 5),
  87.         (5, 6),
  88.         (6, 7),
  89.         (7, 4),
  90.         (0, 4),
  91.         (1, 5),
  92.         (2, 6),
  93.         (3, 7),
  94.     ];
  95.  
  96.     // Cube position
  97.     let mut cube_x = 0.0;
  98.     let mut cube_y = 0.0;
  99.     let mut cube_z = 0.0;
  100.  
  101.     // Square vertices and edges
  102.     let square_vertices = [
  103.         [-2.0, -4.0, -2.0],
  104.         [2.0, -4.0, -2.0],
  105.         [2.0, -4.0, 2.0],
  106.         [-2.0, -4.0, 2.0],
  107.     ];
  108.  
  109.     let square_edges = [
  110.         (0, 1),
  111.         (1, 2),
  112.         (2, 3),
  113.         (3, 0),
  114.     ];
  115.  
  116.     // Camera rotation angle
  117.     let mut angle = 180.0;
  118.  
  119.     // Camera position
  120.     let mut camera_x = 0.0;
  121.     let mut camera_y = 0.0;
  122.  
  123.     let frame_duration = Duration::from_secs_f64(1.0 / FRAME_RATE as f64);
  124.     let mut last_frame_time = Instant::now();
  125.  
  126.     while window.is_open() && !window.is_key_down(Key::Escape) {
  127.         let elapsed = last_frame_time.elapsed();
  128.         if elapsed < frame_duration {
  129.             std::thread::sleep(frame_duration - elapsed);
  130.         }
  131.         last_frame_time = Instant::now();
  132.  
  133.         let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
  134.         window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap();
  135.  
  136.         // Rotate the camera
  137.         //angle += 0.001;
  138.  
  139.         // Handle camera movement
  140.         if window.is_key_down(Key::Up) {
  141.             camera_y += 0.1;
  142.         }
  143.         if window.is_key_down(Key::Down) {
  144.             camera_y -= 0.1;
  145.         }
  146.         if window.is_key_down(Key::Left) {
  147.             camera_x -= 0.1;
  148.         }
  149.         if window.is_key_down(Key::Right) {
  150.             camera_x += 0.1;
  151.         }
  152.         if window.is_key_down(Key::Comma) {
  153.             angle -= 0.01; // Turn camera left
  154.         }
  155.         if window.is_key_down(Key::Period) {
  156.             angle += 0.01; // Turn camera right
  157.         }
  158.  
  159.         // Handle cube movement
  160.         if window.is_key_down(Key::W) {
  161.             cube_z += 0.1;
  162.         }
  163.         if window.is_key_down(Key::S) {
  164.             cube_z -= 0.1;
  165.         }
  166.         if window.is_key_down(Key::A) {
  167.             cube_x -= 0.1;
  168.         }
  169.         if window.is_key_down(Key::D) {
  170.             cube_x += 0.1;
  171.         }
  172.         if window.is_key_down(Key::Q) {
  173.             cube_y -= 0.1; // Move cube down
  174.         }
  175.         if window.is_key_down(Key::E) {
  176.             cube_y += 0.1; // Move cube up
  177.         }
  178.         if window.is_key_down(Key::J) {
  179.             // Rotate cube around the center of its z-axis
  180.             let center_x = (vertices[0][0] + vertices[6][0]) / 2.0;
  181.             let center_y = (vertices[0][1] + vertices[6][1]) / 2.0;
  182.             let center_z = (vertices[0][2] + vertices[6][2]) / 2.0;
  183.             let rotated_vertices = rotate_around_z(vertices, center_x, center_y, center_z, 0.01);
  184.             for i in 0..vertices.len() {
  185.                 vertices[i] = rotated_vertices[i];
  186.             }
  187.         }
  188.         if window.is_key_down(Key::L) {
  189.             // Rotate cube around the center of its z-axis
  190.             let center_x = (vertices[0][0] + vertices[6][0]) / 2.0;
  191.             let center_y = (vertices[0][1] + vertices[6][1]) / 2.0;
  192.             let center_z = (vertices[0][2] + vertices[6][2]) / 2.0;
  193.             let rotated_vertices = rotate_around_z(vertices, center_x, center_y, center_z, -0.01);
  194.             for i in 0..vertices.len() {
  195.                 vertices[i] = rotated_vertices[i];
  196.             }
  197.         }
  198.         if window.is_key_down(Key::I) {
  199.             // Rotate cube around the center of its x-axis
  200.             let center_x = (vertices[0][0] + vertices[6][0]) / 2.0;
  201.             let center_y = (vertices[0][1] + vertices[6][1]) / 2.0;
  202.             let center_z = (vertices[0][2] + vertices[6][2]) / 2.0;
  203.             let rotated_vertices = rotate_around_x(vertices, center_x, center_y, center_z, 0.01);
  204.             for i in 0..vertices.len() {
  205.                 vertices[i] = rotated_vertices[i];
  206.             }
  207.         }
  208.         if window.is_key_down(Key::K) {
  209.             // Rotate cube around the center of its x-axis
  210.             let center_x = (vertices[0][0] + vertices[6][0]) / 2.0;
  211.             let center_y = (vertices[0][1] + vertices[6][1]) / 2.0;
  212.             let center_z = (vertices[0][2] + vertices[6][2]) / 2.0;
  213.             let rotated_vertices = rotate_around_x(vertices, center_x, center_y, center_z, -0.01);
  214.             for i in 0..vertices.len() {
  215.                 vertices[i] = rotated_vertices[i];
  216.             }
  217.         }
  218.         if window.is_key_down(Key::U) {
  219.             // Rotate cube around the center of its y-axis
  220.             let center_x = (vertices[0][0] + vertices[6][0]) / 2.0;
  221.             let center_y = (vertices[0][1] + vertices[6][1]) / 2.0;
  222.             let center_z = (vertices[0][2] + vertices[6][2]) / 2.0;
  223.             let rotated_vertices = rotate_around_y(vertices, center_x, center_y, center_z, 0.01);
  224.             for i in 0..vertices.len() {
  225.                 vertices[i] = rotated_vertices[i];
  226.             }
  227.         }
  228.         if window.is_key_down(Key::O) {
  229.             // Rotate cube around the center of its y-axis
  230.             let center_x = (vertices[0][0] + vertices[6][0]) / 2.0;
  231.             let center_y = (vertices[0][1] + vertices[6][1]) / 2.0;
  232.             let center_z = (vertices[0][2] + vertices[6][2]) / 2.0;
  233.             let rotated_vertices = rotate_around_y(vertices, center_x, center_y, center_z, -0.01);
  234.             for i in 0..vertices.len() {
  235.                 vertices[i] = rotated_vertices[i];
  236.             }
  237.         }
  238.  
  239.         // Project and draw the cube edges
  240.         fn is_front_edge(i: usize, j: usize) -> bool {
  241.             // Define the indices of the front edges
  242.             let front_edges = vec![
  243.                 (0, 1), (1, 2), (2, 3), (3, 0), // Front face
  244.                 //(4, 5), (5, 6), (6, 7), (7, 4), // Back face
  245.                 //(0, 4), (1, 5), (2, 6), (3, 7), // Connecting edges
  246.             ];
  247.  
  248.             // Check if the given indices represent a front edge
  249.             front_edges.contains(&(i, j)) || front_edges.contains(&(j, i))
  250.         }
  251.         fn is_rear_edge(i: usize, j: usize) -> bool {
  252.             // Define the indices of the rear edges
  253.             let rear_edges = vec![
  254.                 (4, 5), (5, 6), (6, 7), (7, 4), // Rear face
  255.                 //(0, 1), (1, 2), (2, 3), (3, 0), // Front face
  256.                 //(0, 4), (1, 5), (2, 6), (3, 7), // Connecting edges
  257.             ];
  258.  
  259.             // Check if the given indices represent a rear edge
  260.             rear_edges.contains(&(i, j)) || rear_edges.contains(&(j, i))
  261.         }
  262.         fn is_bottom_edge(i: usize, j: usize) -> bool {
  263.             // Define the indices of the bottom edges
  264.             let bottom_edges = vec![
  265.                 (4, 5), (5, 6), (6, 7), (7, 4), // Bottom face
  266.                 //(0, 4), (1, 5), (2, 6), (3, 7), // Connecting edges
  267.             ];
  268.  
  269.             // Check if the given indices represent a bottom edge
  270.             bottom_edges.contains(&(i, j)) || bottom_edges.contains(&(j, i))
  271.         }
  272.  
  273.         for &(i, j) in &edges {
  274.             let p1 = project(vertices[i], angle, camera_x, camera_y, cube_x, cube_y, cube_z);
  275.             let p2 = project(vertices[j], angle, camera_x, camera_y, cube_x, cube_y, cube_z);
  276.             if is_front_edge(i, j) {
  277.                 draw_line_with_color(&mut buffer, p1, p2, WIDTH, 0x0000FF); // Set front cube edges to blue
  278.             } else {
  279.                 draw_line(&mut buffer, p1, p2, WIDTH);
  280.             }
  281.         }
  282.  
  283.         // Project and draw the square edges
  284.         for &(i, j) in &square_edges {
  285.             let p1 = project(square_vertices[i], angle, camera_x, camera_y, 0.0, 0.0, -3.0);
  286.             let p2 = project(square_vertices[j], angle, camera_x, camera_y, 0.0, 0.0, -3.0);
  287.             draw_line_with_color(&mut buffer, p1, p2, WIDTH, 0x00FF00); // Set square color to green
  288.         }
  289.  
  290.        
  291.  
  292.         // Draw the x-axis line (red)
  293.         let p1 = project([-1.0, 0.0, 0.0], angle, camera_x, camera_y, 0.0, 0.0, 0.0);
  294.         let p2 = project([1.0, 0.0, 0.0], angle, camera_x, camera_y, 0.0, 0.0, 0.0);
  295.         draw_line_with_color(&mut buffer, p1, p2, WIDTH, 0xFF0000);
  296.  
  297.         // Draw the y-axis line (dark green)
  298.         let p1 = project([0.0, -1.0, 0.0], angle, camera_x, camera_y, 0.0, 0.0, 0.0);
  299.         let p2 = project([0.0, 1.0, 0.0], angle, camera_x, camera_y, 0.0, 0.0, 0.0);
  300.         draw_line_with_color(&mut buffer, p1, p2, WIDTH, 0x006400);
  301.  
  302.         // Draw the z-axis line (cyan blue)
  303.         let p1 = project([0.0, 0.0, -1.0], angle, camera_x, camera_y, 0.0, 0.0, 0.0);
  304.         let p2 = project([0.0, 0.0, 1.0], angle, camera_x, camera_y, 0.0, 0.0, 0.0);
  305.         draw_line_with_color(&mut buffer, p1, p2, WIDTH, 0x00FFFF);
  306.  
  307.         window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap();
  308.     }
  309. }
  310.  
  311. // Project a 3D point onto a 2D plane
  312. fn project(
  313.     point: [f32; 3],
  314.     angle: f32,
  315.     camera_x: f32,
  316.     camera_y: f32,
  317.     cube_x: f32,
  318.     cube_y: f32,
  319.     cube_z: f32,
  320. ) -> (usize, usize) {
  321.     let x = point[0] + cube_x;
  322.     let y = point[1] + cube_y;
  323.     let z = point[2] + cube_z;
  324.  
  325.     let sin_a = angle.sin();
  326.     let cos_a = angle.cos();
  327.  
  328.     let x2 = x * cos_a - z * sin_a;
  329.     let y2 = y + camera_y;
  330.     let z2 = x * sin_a + z * cos_a;
  331.  
  332.     let scale = 2.0 / (z2 + 3.0);
  333.     let x3 = x2 * scale + camera_x;
  334.     let y3 = y2 * scale;
  335.  
  336.     let screen_x = (WIDTH as f32 / 2.0 + x3 * WIDTH as f32 / 4.0) as usize;
  337.     let screen_y = (HEIGHT as f32 / 2.0 - y3 * HEIGHT as f32 / 4.0) as usize;
  338.  
  339.     (screen_x, screen_y)
  340. }
  341.  
  342. fn draw_line(buffer: &mut Vec<u32>, p1: (usize, usize), p2: (usize, usize), width: usize) {
  343.     let (x1, y1) = p1;
  344.     let (x2, y2) = p2;
  345.  
  346.     let dx = (x2 as isize - x1 as isize).abs();
  347.     let dy = (y2 as isize - y1 as isize).abs();
  348.     let sx = if x1 < x2 { 1 } else { -1 };
  349.     let sy = if y1 < y2 { 1 } else { -1 };
  350.     let mut err = dx - dy;
  351.  
  352.     let mut x = x1 as isize;
  353.     let mut y = y1 as isize;
  354.  
  355.     while x != x2 as isize || y != y2 as isize {
  356.         if x >= 0 && x < width as isize && y >= 0 && y < HEIGHT as isize {
  357.             buffer[(y as usize) * width + (x as usize)] = 0xFFFFFF;
  358.         }
  359.  
  360.         let e2 = 2 * err;
  361.         if e2 > -dy {
  362.             err -= dy;
  363.             x += sx;
  364.         }
  365.         if e2 < dx {
  366.             err += dx;
  367.             y += sy;
  368.         }
  369.     }
  370. }
  371.  
  372. fn draw_line_with_color(buffer: &mut Vec<u32>, p1: (usize, usize), p2: (usize, usize), width: usize, color: u32) {
  373.     let (x1, y1) = p1;
  374.     let (x2, y2) = p2;
  375.  
  376.     let dx = (x2 as isize - x1 as isize).abs();
  377.     let dy = (y2 as isize - y1 as isize).abs();
  378.     let sx = if x1 < x2 { 1 } else { -1 };
  379.     let sy = if y1 < y2 { 1 } else { -1 };
  380.     let mut err = dx - dy;
  381.  
  382.     let mut x = x1 as isize;
  383.     let mut y = y1 as isize;
  384.  
  385.     while x != x2 as isize || y != y2 as isize {
  386.         if x >= 0 && x < width as isize && y >= 0 && y < HEIGHT as isize {
  387.             buffer[(y as usize) * width + (x as usize)] = color;
  388.         }
  389.  
  390.         let e2 = 2 * err;
  391.         if e2 > -dy {
  392.             err -= dy;
  393.             x += sx;
  394.         }
  395.         if e2 < dx {
  396.             err += dx;
  397.             y += sy;
  398.         }
  399.     }
  400. }
  401.  
  402. fn rotate_around_z(vertices: [[f32; 3]; 8], center_x: f32, center_y: f32, center_z: f32, angle: f32) -> [[f32; 3]; 8] {
  403.     let sin_a = angle.sin();
  404.     let cos_a = angle.cos();
  405.  
  406.     let mut rotated_vertices = [[0.0; 3]; 8];
  407.     for i in 0..vertices.len() {
  408.         let x = vertices[i][0] - center_x;
  409.         let y = vertices[i][1] - center_y;
  410.         let z = vertices[i][2] - center_z;
  411.  
  412.         rotated_vertices[i][0] = x * cos_a - y * sin_a + center_x;
  413.         rotated_vertices[i][1] = x * sin_a + y * cos_a + center_y;
  414.         rotated_vertices[i][2] = z + center_z;
  415.     }
  416.  
  417.     rotated_vertices
  418. }
  419.  
  420. fn rotate_around_x(vertices: [[f32; 3]; 8], center_x: f32, center_y: f32, center_z: f32, angle: f32) -> [[f32; 3]; 8] {
  421.     let sin_a = angle.sin();
  422.     let cos_a = angle.cos();
  423.  
  424.     let mut rotated_vertices = [[0.0; 3]; 8];
  425.     for i in 0..vertices.len() {
  426.         let x = vertices[i][0] - center_x;
  427.         let y = vertices[i][1] - center_y;
  428.         let z = vertices[i][2] - center_z;
  429.  
  430.         rotated_vertices[i][0] = x + center_x;
  431.         rotated_vertices[i][1] = y * cos_a - z * sin_a + center_y;
  432.         rotated_vertices[i][2] = y * sin_a + z * cos_a + center_z;
  433.     }
  434.  
  435.     rotated_vertices
  436. }
  437.  
  438. fn rotate_around_y(vertices: [[f32; 3]; 8], center_x: f32, center_y: f32, center_z: f32, angle: f32) -> [[f32; 3]; 8] {
  439.     let sin_a = angle.sin();
  440.     let cos_a = angle.cos();
  441.  
  442.     let mut rotated_vertices = [[0.0; 3]; 8];
  443.     for i in 0..vertices.len() {
  444.         let x = vertices[i][0] - center_x;
  445.         let y = vertices[i][1] - center_y;
  446.         let z = vertices[i][2] - center_z;
  447.  
  448.         rotated_vertices[i][0] = x * cos_a + z * sin_a + center_x;
  449.         rotated_vertices[i][1] = y + center_y;
  450.         rotated_vertices[i][2] = -x * sin_a + z * cos_a + center_z;
  451.     }
  452.  
  453.     rotated_vertices
  454. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement