first commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
2324
Cargo.lock
generated
Normal file
2324
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "t3dcube"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pixels = "0.12"
|
||||||
|
winit = "0.28"
|
||||||
|
winit_input_helper = "0.11"
|
||||||
248
src/main.rs
Normal file
248
src/main.rs
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
use winit::{
|
||||||
|
event::{Event, WindowEvent},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3D Point structure
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Point3D {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
z: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cube structure
|
||||||
|
struct Cube {
|
||||||
|
vertices: [Point3D; 8],
|
||||||
|
edges: [(usize, usize); 12],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cube {
|
||||||
|
fn new() -> Self {
|
||||||
|
// Define the 8 vertices of a cube
|
||||||
|
let vertices = [
|
||||||
|
Point3D {
|
||||||
|
x: -1.0,
|
||||||
|
y: -1.0,
|
||||||
|
z: -1.0,
|
||||||
|
}, // 0
|
||||||
|
Point3D {
|
||||||
|
x: 1.0,
|
||||||
|
y: -1.0,
|
||||||
|
z: -1.0,
|
||||||
|
}, // 1
|
||||||
|
Point3D {
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: -1.0,
|
||||||
|
}, // 2
|
||||||
|
Point3D {
|
||||||
|
x: -1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: -1.0,
|
||||||
|
}, // 3
|
||||||
|
Point3D {
|
||||||
|
x: -1.0,
|
||||||
|
y: -1.0,
|
||||||
|
z: 1.0,
|
||||||
|
}, // 4
|
||||||
|
Point3D {
|
||||||
|
x: 1.0,
|
||||||
|
y: -1.0,
|
||||||
|
z: 1.0,
|
||||||
|
}, // 5
|
||||||
|
Point3D {
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
}, // 6
|
||||||
|
Point3D {
|
||||||
|
x: -1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
}, // 7
|
||||||
|
];
|
||||||
|
|
||||||
|
// Define the 12 edges of the cube (vertex indices)
|
||||||
|
let edges = [
|
||||||
|
(0, 1),
|
||||||
|
(1, 2),
|
||||||
|
(2, 3),
|
||||||
|
(3, 0), // Front face
|
||||||
|
(4, 5),
|
||||||
|
(5, 6),
|
||||||
|
(6, 7),
|
||||||
|
(7, 4), // Back face
|
||||||
|
(0, 4),
|
||||||
|
(1, 5),
|
||||||
|
(2, 6),
|
||||||
|
(3, 7), // Connecting edges
|
||||||
|
];
|
||||||
|
|
||||||
|
Self { vertices, edges }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate(&mut self, angle_x: f32, angle_y: f32, angle_z: f32) {
|
||||||
|
for vertex in &mut self.vertices {
|
||||||
|
// Rotate around X axis
|
||||||
|
let y = vertex.y;
|
||||||
|
let z = vertex.z;
|
||||||
|
vertex.y = y * angle_x.cos() - z * angle_x.sin();
|
||||||
|
vertex.z = y * angle_x.sin() + z * angle_x.cos();
|
||||||
|
|
||||||
|
// Rotate around Y axis
|
||||||
|
let x = vertex.x;
|
||||||
|
let z = vertex.z;
|
||||||
|
vertex.x = x * angle_y.cos() + z * angle_y.sin();
|
||||||
|
vertex.z = -x * angle_y.sin() + z * angle_y.cos();
|
||||||
|
|
||||||
|
// Rotate around Z axis
|
||||||
|
let x = vertex.x;
|
||||||
|
let y = vertex.y;
|
||||||
|
vertex.x = x * angle_z.cos() - y * angle_z.sin();
|
||||||
|
vertex.y = x * angle_z.sin() + y * angle_z.cos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project 3D point to 2D screen coordinates
|
||||||
|
fn project(point: Point3D, width: u32, height: u32) -> (i32, i32) {
|
||||||
|
let distance = 5.0;
|
||||||
|
let factor = distance / (distance + point.z);
|
||||||
|
let x = point.x * factor;
|
||||||
|
let y = point.y * factor;
|
||||||
|
|
||||||
|
let screen_x = (x * width as f32 * 0.25) as i32 + (width as i32 / 2);
|
||||||
|
let screen_y = (-y * height as f32 * 0.25) as i32 + (height as i32 / 2);
|
||||||
|
|
||||||
|
(screen_x, screen_y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("Smoothly Spinning 3D Cube")
|
||||||
|
.with_inner_size(winit::dpi::LogicalSize::new(400, 400))
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let window_size = window.inner_size();
|
||||||
|
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
||||||
|
let mut pixels = Pixels::new(window_size.width, window_size.height, surface_texture).unwrap();
|
||||||
|
|
||||||
|
let mut cube = Cube::new();
|
||||||
|
let mut last_frame_time = Instant::now();
|
||||||
|
|
||||||
|
// Rotation speeds in radians per second
|
||||||
|
const ROTATION_SPEED_X: f32 = 0.6; // ~1 rotation every 12.57 seconds
|
||||||
|
const ROTATION_SPEED_Y: f32 = 0.5; // ~1 rotation every 15.71 seconds
|
||||||
|
const ROTATION_SPEED_Z: f32 = 0.4; // ~1 rotation every 20.94 seconds
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
*control_flow = ControlFlow::Poll;
|
||||||
|
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => *control_flow = ControlFlow::Exit,
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::Resized(size),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
pixels.resize_surface(size.width, size.height).unwrap();
|
||||||
|
}
|
||||||
|
Event::RedrawRequested(_) => {
|
||||||
|
// Calculate delta time
|
||||||
|
let now = Instant::now();
|
||||||
|
let delta_time = now - last_frame_time;
|
||||||
|
last_frame_time = now;
|
||||||
|
let delta_seconds = delta_time.as_secs_f32();
|
||||||
|
|
||||||
|
// Clear the screen
|
||||||
|
let frame = pixels.frame_mut();
|
||||||
|
for pixel in frame.chunks_exact_mut(4) {
|
||||||
|
pixel.copy_from_slice(&[0x10, 0x10, 0x10, 0xff]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate based on actual elapsed time
|
||||||
|
cube.rotate(
|
||||||
|
ROTATION_SPEED_X * delta_seconds,
|
||||||
|
ROTATION_SPEED_Y * delta_seconds,
|
||||||
|
ROTATION_SPEED_Z * delta_seconds,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get dimensions
|
||||||
|
let width = window.inner_size().width;
|
||||||
|
let height = window.inner_size().height;
|
||||||
|
|
||||||
|
// Draw cube edges
|
||||||
|
for &(i, j) in &cube.edges {
|
||||||
|
let p1 = cube.vertices[i];
|
||||||
|
let p2 = cube.vertices[j];
|
||||||
|
let (x1, y1) = project(p1, width, height);
|
||||||
|
let (x2, y2) = project(p2, width, height);
|
||||||
|
draw_line_manual(frame, width, x1, y1, x2, y2, [0xff, 0xff, 0xff, 0xff]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if pixels.render().is_err() {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit frame rate
|
||||||
|
let elapsed = now.elapsed();
|
||||||
|
if elapsed < Duration::from_millis(16) {
|
||||||
|
std::thread::sleep(Duration::from_millis(16) - elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
window.request_redraw();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bresenham's line algorithm
|
||||||
|
fn draw_line_manual(
|
||||||
|
frame: &mut [u8],
|
||||||
|
width: u32,
|
||||||
|
mut x0: i32,
|
||||||
|
mut y0: i32,
|
||||||
|
x1: i32,
|
||||||
|
y1: i32,
|
||||||
|
color: [u8; 4],
|
||||||
|
) {
|
||||||
|
let dx = (x1 - x0).abs();
|
||||||
|
let dy = -(y1 - y0).abs();
|
||||||
|
let sx = if x0 < x1 { 1 } else { -1 };
|
||||||
|
let sy = if y0 < y1 { 1 } else { -1 };
|
||||||
|
let mut err = dx + dy;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Only draw if the point is within bounds
|
||||||
|
if x0 >= 0 && x0 < width as i32 && y0 >= 0 && y0 < width as i32 {
|
||||||
|
let idx = ((y0 as u32 * width + x0 as u32) * 4) as usize;
|
||||||
|
if idx + 3 < frame.len() {
|
||||||
|
frame[idx..idx + 4].copy_from_slice(&color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if x0 == x1 && y0 == y1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e2 = 2 * err;
|
||||||
|
if e2 >= dy {
|
||||||
|
err += dy;
|
||||||
|
x0 += sx;
|
||||||
|
}
|
||||||
|
if e2 <= dx {
|
||||||
|
err += dx;
|
||||||
|
y0 += sy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user