#![deny(unsafe_code)] use crate::error::*; use crate::graphics::Render; use crate::linear_algebra::{ Vec3, Vec4, Transformation }; use crate::shader_data::{ Vertex, VertexPushBlock }; use std::f32::consts::{ TAU }; use vulkanalia::Device; use vulkanalia::vk::{ self, HasBuilder, DeviceV1_0 }; #[allow(unsafe_code)] pub fn generate_scene_commands<'a>(image_index: usize, time: f32, render: &'a Render, device: &Device, extent: &vk::Extent2D) -> Result<&'a vk::CommandBuffer> { let frame = &render.per_frame[image_index]; let command_buffer = &frame.command_buffer; let framebuffer = &frame.framebuffer; let descriptor_set = &frame.descriptor_set; let inheritance_info = vk::CommandBufferInheritanceInfo::builder(); let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() .flags(vk::CommandBufferUsageFlags::empty()) .inheritance_info(&inheritance_info); unsafe { device.begin_command_buffer(*command_buffer, &command_buffer_begin_info) }?; let render_area = vk::Rect2D::builder() .offset(vk::Offset2D::default()) .extent(*extent); let color_clear_value = vk::ClearValue { color: vk::ClearColorValue { float32: [0.0, 0.0, 0.0, 1.0] } }; let depth_clear_value = vk::ClearValue { depth_stencil: vk::ClearDepthStencilValue { depth: 1.0, stencil: 0, } }; let clear_values = [color_clear_value, depth_clear_value]; let begin_pass_info = vk::RenderPassBeginInfo::builder() .render_pass(render.render_pass) .framebuffer(*framebuffer) .render_area(render_area) .clear_values(&clear_values); unsafe { device.cmd_begin_render_pass(*command_buffer, &begin_pass_info, vk::SubpassContents::INLINE) }; unsafe { device.cmd_bind_pipeline(*command_buffer, vk::PipelineBindPoint::GRAPHICS, render.pipeline) }; // Please notice the magic constant 0. This is a zero-based index into // the array of descriptor set layouts passed to create_pipeline_layout() // in init_pipeline() in render.rs. unsafe { device.cmd_bind_descriptor_sets(*command_buffer, vk::PipelineBindPoint::GRAPHICS, render.pipeline_layout, 0, &[*descriptor_set], &[]) }; if let Some(texture) = &render.texture { texture.make_active(device, render, command_buffer); } if let Some(model) = &render.model { model.make_active(device, render, command_buffer); let (scale, mut transformation) = demo_spin_transformation(time); apply_model_transformation(device, render, command_buffer, &scale, &transformation); model.render(device, render, command_buffer); transformation.translation = transformation.translation.add( &Vec3::new(0.0, 4.0, 0.0)); apply_model_transformation(device, render, command_buffer, &scale, &transformation); model.render(device, render, command_buffer); transformation.translation = transformation.translation.add( &Vec3::new(0.0, -8.0, 0.0)); apply_model_transformation(device, render, command_buffer, &scale, &transformation); model.render(device, render, command_buffer); } unsafe { device.cmd_end_render_pass(*command_buffer) }; unsafe { device.end_command_buffer(*command_buffer) }?; Ok(command_buffer) } fn demo_spin_transformation(time: f32) -> (Vec3, Transformation) { let scale = Vec3::new(1.0, 1.0, 1.0); let transformation = Transformation { rotation: Vec4::rotation_quaternion(&Vec3::new(0.0, 1.0, 0.0), time % TAU), translation: Vec3::new(0.0, 0.0, 0.0), }; (scale, transformation) } #[allow(unsafe_code)] fn apply_model_transformation(device: &Device, render: &Render, command_buffer: &vk::CommandBuffer, scale: &Vec3, transformation: &Transformation) { let push_block = VertexPushBlock:: { scale: scale.clone(), model: transformation.clone(), }; let size = size_of::>(); let push_block_bytes = unsafe { std::slice::from_raw_parts(&push_block as *const VertexPushBlock as *const u8, size) }; unsafe { device.cmd_push_constants(*command_buffer, render.pipeline_layout, vk::ShaderStageFlags::VERTEX, 0, push_block_bytes) }; }