You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Trac3r-rust/src/canvas.rs

351 lines
10 KiB

use crate::vertex_2d::{ColoredVertex2D, Vertex2D};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
use crate::Sprite;
use std::collections::HashMap;
use vulkano::buffer::{BufferAccess, CpuAccessibleBuffer, BufferUsage};
use std::sync::Arc;
use vulkano::format::{ClearValue, Format};
use vulkano::framebuffer::FramebufferAbstract;
use vulkano::device::{Device, Queue};
use vulkano::instance::PhysicalDevice;
use vulkano::image::immutable::ImmutableImage;
use crate::util::shader_kernels::ShaderKernels;
use vulkano::image::{Dimensions, ImageUsage, ImageAccess, ImageDimensions};
use vulkano::sampler::{Sampler, SamplerAddressMode, MipmapMode, Filter};
use vulkano::descriptor::DescriptorSet;
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use std::path::PathBuf;
use image::GenericImageView;
use crate::util::compute_image::ComputeImage;
// Canvas is the accumulator of Sprites for drawing
// Needs to know:
// textured?
// colored?
// vertices
/*
If it is textured. It needs to be rendered with the texture shader which requires a separate
graphics pipeline. Might as well have a new render pass as well.
I need a second version of shaderkernels
So framebuffer is tied to the swapchains images as well as the renderpass
it appears that renderpass is tied to the individual shader
*/
// I want to be able to draw 2d sprites.
// These sprites might be textured or a single color
// All of the single colors will be grouped into one batch using colored vertices.
// The rest will be grouped by their texture and run individually
/*
vertex count differing is a big nono
ColoredVertex2D
Non-Textured
Vertex2D
Textured
Colored, vs non-colored:
Calling the color() field or not
I just wanna
*/
pub trait Vertex {
fn position(&self) -> (f32, f32) {
(0.0,0.0)
}
fn color(&self) -> Option<(f32, f32, f32, f32)> {
Some((0.,0.,0.,0.))
}
fn textured(&self) -> bool {
false
}
}
impl Vertex for ColoredVertex2D {
fn position(&self) -> (f32, f32) {
(0.0,0.0)
}
fn color(&self) -> Option<(f32, f32, f32, f32)> {
Some((0.,0.,0.,0.))
}
fn textured(&self) -> bool {
false
}
}
pub trait Drawable {
fn get_vertices(&self) -> Vec<(f32, f32)>;
fn get_color(&self) -> (f32, f32, f32, f32);
fn get_texture_id(&self) -> Option<String>;
}
/*
OASIJDOQIWEJFOWIEJFOWIEJFOWEIJFOIWEJFOIW
Right now I'm in the middle of adding texture ownership to the canvas.
I'm aiming at being able to load them on the fly from what texture name (String) the
sprite is requesting. This might be too slow though as I can't really avoid a lookup table
somewhere in the code.
*/
// Need three types of shaders. Solid, Textured, Compute
#[derive(PartialEq)]
#[derive(Eq)]
#[derive(Hash)]
pub enum ShaderType {
SOLID = 0,
TEXTURED = 1,
COMPUTE = 2
}
pub struct Canvas {
colored_drawables : Vec<ColoredVertex2D>,
textured_drawables: HashMap<String, Vec<Vertex2D>>,
vertex_buffers: Vec<Arc<(dyn BufferAccess + std::marker::Send + std::marker::Sync + 'static)>>,
shader_kernels: HashMap<ShaderType, ShaderKernels>,
textures: Vec<Arc<ImmutableImage<Format>>>,
}
impl Canvas {
// needs to take in the texture list
pub fn new() -> Canvas {
Canvas {
colored_drawables: vec![],
textured_drawables: Default::default(),
vertex_buffers: vec![],
shader_kernels: HashMap::new(),
textures: vec![]
}
}
fn get_texture_from_file(image_filename: String, queue: Arc<Queue>) -> Arc<ImmutableImage<Format>> {
let project_root =
std::env::current_dir()
.expect("failed to get root directory");
let mut compute_path = project_root.clone();
compute_path.push(PathBuf::from("resources/images/"));
compute_path.push(PathBuf::from(image_filename));
let img = image::open(compute_path).expect("Couldn't find image");
let xy = img.dimensions();
let data_length = xy.0 * xy.1 * 4;
let pixel_count = img.raw_pixels().len();
let mut image_buffer = Vec::new();
if pixel_count != data_length as usize {
println!("Creating apha channel...");
for i in img.raw_pixels().iter() {
if (image_buffer.len() + 1) % 4 == 0 {
image_buffer.push(255);
}
image_buffer.push(*i);
}
image_buffer.push(255);
} else {
image_buffer = img.raw_pixels();
}
let (texture, tex_future) = ImmutableImage::from_iter(
image_buffer.iter().cloned(),
Dimensions::Dim2d { width: xy.0, height: xy.1 },
Format::R8G8B8A8Srgb,
queue.clone()
).unwrap();
texture
}
pub fn load_texture_from_filename(&mut self, filename: String, queue: Arc<Queue>) {
let texture = Canvas::get_texture_from_file(filename.clone(), queue.clone());
self.textures.push(texture);
let texture1 = Canvas::get_texture_from_file(String::from("button.png"), queue.clone());
self.textures.push(texture1);
}
pub fn draw(&mut self, drawable: &dyn Drawable) {
match drawable.get_texture_id() {
Some(id) => {
// This dont work
self.textured_drawables.get(&id).unwrap();
},
None => {
let colors = drawable.get_color();
self.colored_drawables.extend(
drawable.get_vertices().iter().map(|n|
ColoredVertex2D {
position: [n.0, n.1],
color: [colors.0, colors.1, colors.2, colors.3]
}
)
);
}
}
}
pub fn allocate_vertex_buffers(&mut self, device: Arc<Device>) {
self.vertex_buffers.push(
CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::vertex_buffer(),
self.colored_drawables.iter().cloned()
).unwrap()
);
}
// I guess these go out as an array. So I can add multiple descriptor sets
// So probably needs to know which shaders are for textures
// needs to associate this descriptor set to a texture (key-pair, tuple)
//
// So this is fine for now. But I want to be able to:
// Choose which texture I want to add to this descriptor set.
// Add multiple textures
// Choose which shader and pipeline it should run on
fn get_texture_descriptor_set(&mut self, device: Arc<Device>) -> Box<dyn DescriptorSet + Send + Sync> {
let sampler = Sampler::new(device.clone(), Filter::Linear, Filter::Linear,
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap();
let o : Box<dyn DescriptorSet + Send + Sync> = Box::new(
PersistentDescriptorSet::start(
self.shader_kernels.get(&ShaderType::TEXTURED).unwrap().clone().get_pipeline(), 0
)
.add_sampled_image(self.textures.get(0).unwrap().clone(), sampler.clone()).unwrap()
.build().unwrap());
o
}
// The image set is the containing object for all texture and image hooks.
fn get_compute_swap_descriptor_set(&mut self,
device: Arc<Device>,
compute_image: &ComputeImage) -> Box<dyn DescriptorSet + Send + Sync> {
let sampler = Sampler::new(device.clone(), Filter::Linear, Filter::Linear,
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap();
let o : Box<dyn DescriptorSet + Send + Sync> = Box::new(
PersistentDescriptorSet::start(
self.shader_kernels.get(&ShaderType::COMPUTE).clone().unwrap().clone().get_pipeline(), 0
)
.add_image(compute_image.clone().get_swap_buffer().clone()).unwrap()
.build().unwrap());
o
}
/*
So I need the image set in order to get my texture or compute texture
Done
compute image currently holds the set for compute and its swap buffer
but during a descriptor set build, we corrow the compute_image and take
it's swap buffer
vkprocessor creates the image sets for draw calls
takes the pipeline from the ShaderKernel - Which we own
adds vk processor owned texture - Not any more
adds compute image taken from the ComputeImage - Still true
we have shaderkernel in here so thats fine
Who should own the texture?
I would need to borrow it each time I created an image set...
These are tied very closely to the input output of a shader, which we would own
I just need to add a third option on sprite and allow it to have a swap buffer
*/
pub fn draw_commands(&mut self,
command_buffer: AutoCommandBufferBuilder,
framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
image_num: usize) -> AutoCommandBufferBuilder {
// Specify the color to clear the framebuffer with i.e. blue
let clear_values = vec!(ClearValue::Float([0.0, 0.0, 1.0, 1.0]));
let dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
let mut command_buffer = command_buffer.begin_render_pass(
framebuffers[image_num].clone(), false, clear_values.clone()
).unwrap();
// for i in self.shader_kernels {
// command_buffer = command_buffer.draw(
// i.clone().unwrap().get_pipeline(),
// &dynamic_state.clone(), self.vertex_buffers,
// vec![self.get_image_set()], ()
// ).unwrap();
// }
//
// .draw(self.shader_kernels.clone().unwrap().get_pipeline(),
// &dynamic_state.clone(), self.vertex_buffers,
// vec![self.get_gui_image_set()], ())
// .unwrap();
//
command_buffer
.end_render_pass()
.unwrap()
}
}