use lonsdaleite::*; use png; use std::fs::File; use std::os::raw::c_void; 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("Textured Quad") .with_inner_size(PhysicalSize::new(1028, 256)) .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 quad_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 &[ // bottom left -1.0f32, -1.0, 0.0, 1.0, // position 0.0, 1.0, 0.0, 0.0, // texture coord // bottom right 1.0, -1.0, 0.0, 1.0, // position 1.0, 1.0, 0.0, 0.0, // texture coord // top right 1.0, 1.0, 0.0, 1.0, // position 1.0, 0.0, 0.0, 0.0, // texture coord // bottom left -1.0f32, -1.0, 0.0, 1.0, // position 0.0, 1.0, 0.0, 0.0, // texture coord // top right 1.0, 1.0, 0.0, 1.0, // position 1.0, 0.0, 0.0, 0.0, // texture coord // top left -1.0, 1.0, 0.0, 1.0, // position 0.0, 0.0, 0.0, 0.0, // texture coord ], ); let decoder = png::Decoder::new(File::open("assets/lonsdaleite.png").unwrap()); let (info, mut reader) = decoder.read_info().unwrap(); let mut buffer = vec![0; info.buffer_size()]; reader.next_frame(&mut buffer).unwrap(); let sampler: Sampler = device.new_sampler(&SamplerDescriptor { min_filter: SamplerFilter::Nearest, mag_filter: SamplerFilter::Nearest, mip_filter: Some(SamplerFilter::Nearest), address_mode: Size3D { width: SamplerAddressMode::ClampToEdge, height: SamplerAddressMode::ClampToEdge, depth: SamplerAddressMode::ClampToEdge, }, border_colour: SamplerBorderColour::TransparentBlack, max_anisotropy: 1, lod_min_clamp: 0.0, lod_max_clamp: 100000.0, lod_average_enabled: false, support_argument_buffers: false, compare_function: CompareFunction::Never, }); let texture: Texture = device.new_texture(&TextureDescriptor { texture_type: TextureType::Texture2D, pixel_format: PixelFormat::RGBA8Unorm, size: Size3D { width: info.width as u64, height: info.height as u64, depth: 1, }, mipmap_level: 1, array_length: 1, sample_count: 1, cache_mode: CPUCacheMode::Default, storage_mode: StorageMode::Managed, usage: TextureUsage::ShaderRead, }); unsafe { let data = buffer.as_ptr(); texture.replace_contents( 0, 4 * info.width as u64, Region { origin: Size3D { width: 0, height: 0, depth: 0, }, size: Size3D { width: info.width as u64, height: info.height as u64, depth: 1, }, }, data as *const c_void, ); }; let library: Library = device.new_library(&LibraryDescriptor::Source(include_str!("texture.metal"))); let vertex = library.get_function("vertex_shader"); let fragment = library.get_function("fragment_shader"); let render_pipeline: RenderPipeline = device.new_render_pipeline(&RenderPipelineDescriptor { vertex_function: &vertex, fragment_function: &fragment, 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)], fragment_buffers_mutability: &[], primitive_topology: None, }); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; match event { Event::RedrawRequested(_) => { let command_buffer: CommandBuffer = command_queue.new_command_buffer(); if let Some(framebuffer) = Framebuffer::from_surface(&surface) { 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, &quad_data); encoder.set_fragment_sampler(0, &sampler, 0.0f32..100000.0); encoder.set_fragment_texture(0, &texture); encoder.draw(Primitive::Triangles, 0, 6); 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) => { // } WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; } _ => {} } } _ => {} } }); }