use lonsdaleite::*; use cgmath::prelude::*; use cgmath::{perspective, Deg, Matrix4, Rad, Vector3}; use std::time::{Duration, Instant}; use winit::{ dpi::PhysicalSize, event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, }; fn main() { let event_loop: EventLoop<()> = EventLoop::new(); let window: Window = WindowBuilder::new() .with_title("3D Triangle") .with_inner_size(PhysicalSize::new(1280, 720)) .with_resizable(true) .build(&event_loop) .unwrap(); let devices: Vec = Device::enumerate(); let device: Device = devices.into_iter().find_map(|device| Some(device)).unwrap(); let surface: Surface = device.new_surface(&window); let command_queue: CommandQueue = device.new_command_queue(); let triangle_data: Buffer = device.new_buffer( &BufferDescriptor { cache_mode: CPUCacheMode::Default, storage_mode: StorageMode::Managed, }, // if the floats aren't a FloatVec4, // add an extra float for padding &[ 1.0f32, -1.0, 0.0, 1.0, // position 1.0, 0.0, 0.0, 1.0, // colour -1.0, -1.0, 0.0, 1.0, // position 0.0, 0.0, 1.0, 1.0, // colour 0.0, 1.0, 0.0, 1.0, // position 0.0, 1.0, 0.0, 1.0, // colour ], ); let projection = perspective( Deg(70.0), (window.inner_size().width as f32) / (window.inner_size().height as f32), 0.1, 1000.0, ); let mut projection_buffer: Buffer = device.new_buffer( &BufferDescriptor { cache_mode: CPUCacheMode::Default, storage_mode: StorageMode::Managed, }, &[ // projection matrix projection.x.x, projection.x.y, projection.x.z, projection.x.w, projection.y.x, projection.y.y, projection.y.z, projection.y.w, projection.z.x, projection.z.y, projection.z.z, projection.z.w, projection.w.x, projection.w.y, projection.w.z, projection.w.w, ], ); let mut transformation_matrix: Matrix4 = Matrix4::identity(); let mut transformation_buffer: Buffer = device.new_buffer( &BufferDescriptor { cache_mode: CPUCacheMode::Default, storage_mode: StorageMode::Managed, }, &[ transformation_matrix.x.x, transformation_matrix.x.y, transformation_matrix.x.z, transformation_matrix.x.w, transformation_matrix.y.x, transformation_matrix.y.y, transformation_matrix.y.z, transformation_matrix.y.w, transformation_matrix.z.x, transformation_matrix.z.y, transformation_matrix.z.z, transformation_matrix.z.w, transformation_matrix.w.x, transformation_matrix.w.y, transformation_matrix.w.z, transformation_matrix.w.w, ], ); let library: Library = device.new_library(&LibraryDescriptor::Source(include_str!("triangle.metal"))); let vertex_function: Function = library.get_function("vertex_shader"); let fragment_function: Function = library.get_function("fragment_shader"); let render_pipeline: RenderPipeline = device.new_render_pipeline(&RenderPipelineDescriptor { vertex_function: &vertex_function, fragment_function: &fragment_function, vertex_attrib_layouts: &[ &AttributeLayout { offset: 0, buffer_index: 0, format: ShaderFormat::FloatVec4, }, &AttributeLayout { offset: 16, buffer_index: 0, format: ShaderFormat::FloatVec4, }, ], vertex_buffer_layouts: &[&BufferLayout { stride: 16, step_function: StepFunction::PerVertex, step_rate: 1, }], depth_attachment_format: PixelFormat::Depth32Float_Stencil8, stencil_attachment_format: PixelFormat::Depth32Float_Stencil8, sample_count: 1, colour_attachments: &[&RenderPipelineColourAttachmentDescriptor { format: PixelFormat::BGRA8Unorm, blending: true, rgb_blend: BlendDescriptor { operation: BlendOperation::Add, src_factor: BlendFactor::SrcAlpha, dst_factor: BlendFactor::OneMinusSrcAlpha, }, alpha_blend: BlendDescriptor { operation: BlendOperation::Add, src_factor: BlendFactor::One, dst_factor: BlendFactor::OneMinusSrcAlpha, }, write_mask: ColourWriteMask::Red | ColourWriteMask::Green | ColourWriteMask::Blue | ColourWriteMask::Alpha, }], vertex_buffers_mutability: &[ MutabilityTable(0, Mutability::Immutable), MutabilityTable(1, Mutability::Mutable), MutabilityTable(1, Mutability::Mutable), ], fragment_buffers_mutability: &[], primitive_topology: None, }); let mut time = 0.0f32; let length = Duration::from_millis(17); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::WaitUntil(Instant::now() + length); match event { Event::RedrawRequested(_) => { let command_buffer: CommandBuffer = command_queue.new_command_buffer(); if let Some(framebuffer) = Framebuffer::from_surface(&surface) { transformation_matrix = Matrix4::from_translation(Vector3 { x: time.sin(), y: 0.0, z: -3.0, }); transformation_matrix = transformation_matrix * Matrix4::from_axis_angle( Vector3 { x: 0.0, y: 1.0, z: 0.0, }, Rad(time), ); transformation_buffer.modify_data(&[ transformation_matrix.x.x, transformation_matrix.x.y, transformation_matrix.x.z, transformation_matrix.x.w, transformation_matrix.y.x, transformation_matrix.y.y, transformation_matrix.y.z, transformation_matrix.y.w, transformation_matrix.z.x, transformation_matrix.z.y, transformation_matrix.z.z, transformation_matrix.z.w, transformation_matrix.w.x, transformation_matrix.w.y, transformation_matrix.w.z, transformation_matrix.w.w, ]); time += 0.01; let encoder: RenderCommandEncoder = command_buffer.new_render_command_encoder(&RenderPassDescriptor { colour_attachments: &[RenderPassColourAttachmentDescriptor { clear_colour: [0.0, 0.0, 0.0, 1.0], }], framebuffer: &framebuffer, load_op: LoadOperation::Clear, store_op: StoreOperation::Store, resolve_texture: None, stencil_resolve_filter: StencilResolveFilter::Sample0, clear_depth: 0.0, clear_stencil: 0, }); encoder.set_pipeline(&render_pipeline); encoder.set_vertex_buffer(0, 0, &triangle_data); encoder.set_vertex_buffer(1, 0, &projection_buffer); encoder.set_vertex_buffer(2, 0, &transformation_buffer); encoder.draw(Primitive::Triangles, 0, 3); encoder.end_render_encoding(); command_buffer.present(&framebuffer); command_buffer.commit(); } } Event::MainEventsCleared => { window.request_redraw(); } Event::WindowEvent { window_id: _, event, } => { match event { WindowEvent::Resized(new_size) => { let projection = cgmath::perspective( cgmath::Deg(70.0), (new_size.width as f32) / (new_size.height as f32), 0.1, 1000.0, ); projection_buffer = device.new_buffer( &BufferDescriptor { cache_mode: CPUCacheMode::Default, storage_mode: StorageMode::Managed, }, &[ // projection matrix projection.x.x, projection.x.y, projection.x.z, projection.x.w, projection.y.x, projection.y.y, projection.y.z, projection.y.w, projection.z.x, projection.z.y, projection.z.z, projection.z.w, projection.w.x, projection.w.y, projection.w.z, projection.w.w, ], ); } WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; } _ => {} } } _ => {} } }); }