use std::num::NonZeroU32;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::thread;
use crate::high_level_fighter::HighLevelFighter;
use crate::renderer::app::state::InvulnerableType;
use crate::renderer::camera::Camera;
use crate::renderer::draw::draw_frame;
use crate::renderer::wgpu_state::WgpuState;
pub async fn render_gif(
state: &mut WgpuState,
high_level_fighter: &HighLevelFighter,
subaction_index: usize,
) -> Receiver<Vec<u8>> {
let width: u16 = 400;
let height: u16 = 300;
let subaction = &high_level_fighter.subactions[subaction_index];
let (frames_tx, frames_rx) = mpsc::channel();
let (gif_tx, gif_rx) = mpsc::channel();
let subaction_len = subaction.frames.len();
thread::spawn(move || {
let mut result = vec![];
{
let mut encoder = gif::Encoder::new(&mut result, width, height, &[]).unwrap();
for _ in 0..subaction_len {
let mut frame_data: Vec<u8> = frames_rx.recv().unwrap();
let gif_frame =
gif::Frame::from_rgba_speed(width as u16, height as u16, &mut frame_data, 30);
encoder.write_frame(&gif_frame).unwrap();
}
encoder
.write_extension(gif::ExtensionData::Repetitions(gif::Repeat::Infinite))
.unwrap();
}
gif_tx.send(result).unwrap();
});
for (frame_index, _) in subaction.frames.iter().enumerate() {
let framebuffer_extent = wgpu::Extent3d {
width: width as u32,
height: height as u32,
depth_or_array_layers: 1,
};
let framebuffer_descriptor = &wgpu::TextureDescriptor {
size: framebuffer_extent,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: state.format,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
label: None,
};
let framebuffer = state.device.create_texture(framebuffer_descriptor);
let framebuffer_copy_view = wgpu::ImageCopyTexture {
texture: &framebuffer,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
};
let bytes_per_pixel = std::mem::size_of::<u32>() as u32;
let real_bytes_per_row = width as u32 * bytes_per_pixel;
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT;
let padded_bytes_per_row_padding = (align - real_bytes_per_row % align) % align;
let padded_bytes_per_row = real_bytes_per_row + padded_bytes_per_row_padding;
let framebuffer_out_descriptor = &wgpu::BufferDescriptor {
size: padded_bytes_per_row as u64 * height as u64,
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
label: None,
mapped_at_creation: false,
};
let framebuffer_out = state.device.create_buffer(framebuffer_out_descriptor);
let framebuffer_out_copy_view = wgpu::ImageCopyBuffer {
buffer: &framebuffer_out,
layout: wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(NonZeroU32::new(padded_bytes_per_row).unwrap()),
rows_per_image: None,
},
};
let camera = Camera::new(subaction, width, height);
let mut command_encoder = draw_frame(
state,
&framebuffer.create_view(&wgpu::TextureViewDescriptor::default()),
width as u32,
height as u32,
false,
false,
false,
&InvulnerableType::Hit,
subaction,
frame_index,
&camera,
); command_encoder.copy_texture_to_buffer(
framebuffer_copy_view,
framebuffer_out_copy_view,
framebuffer_extent,
);
state.queue.submit(Some(command_encoder.finish()));
let frames_tx = frames_tx.clone();
let framebuffer_out_slice = framebuffer_out.slice(..);
let read = framebuffer_out_slice.map_async(wgpu::MapMode::Read);
state.poll();
match read.await {
Ok(()) => {
let mut padded_buffer = framebuffer_out_slice.get_mapped_range().to_vec();
for y in 1..height as usize {
let padded_offset = y * padded_bytes_per_row as usize;
let real_offset = y * real_bytes_per_row as usize;
padded_buffer.copy_within(
padded_offset..padded_offset + real_bytes_per_row as usize,
real_offset,
)
}
let real_buffer =
padded_buffer[0..real_bytes_per_row as usize * height as usize].to_vec();
frames_tx.send(real_buffer).unwrap();
}
Err(error) => panic!("map_read failed: {:?}", error),
}
}
gif_rx
}
pub fn render_gif_blocking(
state: &mut WgpuState,
high_level_fighter: &HighLevelFighter,
subaction_index: usize,
) -> Vec<u8> {
let gif_rx =
futures::executor::block_on(render_gif(state, high_level_fighter, subaction_index));
gif_rx.recv().unwrap()
}