diff --git a/models/FiraCode-Regular.ttf b/models/FiraCode-Regular.ttf new file mode 100644 index 0000000..0d57068 Binary files /dev/null and b/models/FiraCode-Regular.ttf differ diff --git a/src/game/mod.rs b/src/game/mod.rs index 810e257..7258f84 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,6 +1,6 @@ use std::time::SystemTime; use cgmath::{Deg, Euler, Quaternion, vec3}; -use glyph_brush::{BrushAction, BrushError, GlyphBrushBuilder, Section, Text}; +use glyph_brush::{BrushAction, BrushError, GlyphBrush, GlyphBrushBuilder, GlyphVertex, Section, Text}; use glyph_brush::ab_glyph::FontArc; use vulkano::format::Format; use vulkano::sampler::{Filter, SamplerAddressMode}; @@ -11,7 +11,7 @@ use player::Player; use crate::{config::LogConfig, vulkan}; use crate::input::InputState; -use crate::vulkan::{Game, MeshHandle, TextVertex, Vertex, VulkanRenderer}; +use crate::vulkan::{Game, MeshHandle, TextVertex, Texture, Vertex, VulkanRenderer}; use crate::vulkan::gameobject::{GameObject, GameObjectHandle, Updatable}; use crate::vulkan::mesh::{self, CPUMesh, CPUVertex}; use crate::vulkan::pipelines::vs::ty::ObjectUniformData; @@ -23,11 +23,13 @@ pub struct TestGame { pub input: InputState, pub player: Player, pub game_objects: Vec, + pub text_objects: Vec, pub log_config: LogConfig, pub texture_index_counter: usize, pub last_time: f32, pub components: Vec>, pub paused: bool, + pub font: FontArc } impl Game for TestGame { @@ -73,7 +75,8 @@ impl Game for TestGame { } if self.input.button_just_pressed("test") { - self.paused = !self.paused; + // self.paused = !self.paused; + self.text_objects[0].update_text("yeet", 100.0, renderer); } // Custom game object stuff @@ -107,11 +110,13 @@ impl TestGame { input: InputState::new(toml_path, log_config), player: Player::new(), game_objects: vec![], + text_objects: vec![], log_config, texture_index_counter: 0, last_time: 0.0, components: vec![], paused: false, + font: FontArc::try_from_slice(include_bytes!("../../models/FiraCode-Regular.ttf")).unwrap(), } } @@ -119,60 +124,8 @@ impl TestGame { load_level("levels/test.lvl", self, renderer).unwrap(); println!("Game loaded!"); - let font = FontArc::try_from_slice(include_bytes!("../../models/OverpassRegular.ttf")).unwrap(); - let mut glyph_brush = GlyphBrushBuilder::using_font(font).build(); - - let mut tex_min_size = None; - let mut tex_max_size = None; - - glyph_brush.queue(Section::default().add_text(Text::new("penis lol").with_scale(100.))); - match glyph_brush.process_queued(|rect, text_data| { - renderer.upload_texture(text_data, rect.width(), rect.height(), Format::R8Unorm, Filter::Nearest, SamplerAddressMode::ClampToEdge, renderer.device.clone()); - self.texture_index_counter += 1; - tex_max_size = Some(u32::max(rect.width(), rect.height())); - tex_min_size = Some(u32::min(rect.width(), rect.height())); - }, |vertex_data| { - println!("VD: {:?}", vertex_data); - let result = vec![ - TextVertex { position: [vertex_data.pixel_coords.min.x, vertex_data.pixel_coords.min.y, 0.], uv: [vertex_data.tex_coords.min.x, vertex_data.tex_coords.min.y] }, - TextVertex { position: [vertex_data.pixel_coords.min.x, vertex_data.pixel_coords.max.y, 0.], uv: [vertex_data.tex_coords.min.x, vertex_data.tex_coords.max.y] }, - TextVertex { position: [vertex_data.pixel_coords.max.x, vertex_data.pixel_coords.min.y, 0.], uv: [vertex_data.tex_coords.max.x, vertex_data.tex_coords.min.y] }, - TextVertex { position: [vertex_data.pixel_coords.max.x, vertex_data.pixel_coords.max.y, 0.], uv: [vertex_data.tex_coords.max.x, vertex_data.tex_coords.max.y] }, - ]; - result - }) { - Ok(BrushAction::Draw(quads)) => { - let mut final_vertices = vec![]; - let mut final_indices: Vec = vec![]; - let mut index_offset = 0; - for quad in quads { - final_vertices.append(&mut quad.iter().map(|v| CPUVertex::VertexText(TextVertex { position: v.position, uv: [v.uv[0], v.uv[1] * (tex_max_size.unwrap() as f32) / (tex_min_size.unwrap() as f32) ] })).collect()); - final_indices.append(&mut [0, 2, 3, 0, 3, 1].iter().map(|x| *x + index_offset).collect()); - index_offset += quad.len() as u32; - } - let mesh = CPUMesh { - vertices: final_vertices, - indices: final_indices, - local_texture_index: Some(self.texture_index_counter - 1), - local_normal_map_index: None, - name: Some("font_texture".to_string()), - }; - let mesh_index = renderer.upload_mesh(mesh, None); - let mesh_handle = MeshHandle { - index: mesh_index, - diffuse_handle: self.texture_index_counter - 1, - normal_handle: None, - original_path: None, - pipeline_index: 1 - }; - let mut game_object_handle = self.add_game_object(renderer, mesh_handle); - game_object_handle.get_game_object_mut(renderer).unwrap().scale = vec3(0.1, 0.1, 0.1); - self.game_objects.push(game_object_handle); - }, - Ok(BrushAction::ReDraw) => {}, - Err(BrushError::TextureTooSmall { suggested: _ }) => { println!("texture too small!"); }, - } - + let text_obj = self.create_text_object(renderer, "Nice font", 24.); + self.text_objects.push(text_obj); } pub fn offset_texture_id(&mut self, local_tex_id: Option) -> usize { @@ -208,7 +161,8 @@ impl TestGame { for doc_image in document.images() { let texture_start_time = SystemTime::now(); - vulkan::dds::upload_texture_from_file(&format!("models/textures/{}.dds", doc_image.name().unwrap()), renderer).unwrap(); + let texture = vulkan::dds::upload_texture_from_file(&format!("models/textures/{}.dds", doc_image.name().unwrap()), renderer).unwrap(); + renderer.game_data.textures.push(texture); self.texture_index_counter += 1; if self.log_config.mesh_load_info { @@ -225,6 +179,74 @@ impl TestGame { self.game_objects.last().unwrap().clone() } + fn convert_vertices(vertex_data: GlyphVertex) -> Vec { + // println!("VD: {:?}", vertex_data); + let result = vec![ + TextVertex { position: [vertex_data.pixel_coords.min.x, vertex_data.pixel_coords.min.y, 0.], uv: [vertex_data.tex_coords.min.x, vertex_data.tex_coords.min.y] }, + TextVertex { position: [vertex_data.pixel_coords.min.x, vertex_data.pixel_coords.max.y, 0.], uv: [vertex_data.tex_coords.min.x, vertex_data.tex_coords.max.y] }, + TextVertex { position: [vertex_data.pixel_coords.max.x, vertex_data.pixel_coords.min.y, 0.], uv: [vertex_data.tex_coords.max.x, vertex_data.tex_coords.min.y] }, + TextVertex { position: [vertex_data.pixel_coords.max.x, vertex_data.pixel_coords.max.y, 0.], uv: [vertex_data.tex_coords.max.x, vertex_data.tex_coords.max.y] }, + ]; + result + } + + pub fn create_text_object(&mut self, renderer: &mut VulkanRenderer, text: &str, size: f32) -> TextObject { + let mut tex_min_size = None; + let mut tex_max_size = None; + let mut uploaded_texture = None; + let mut uploaded_game_object = None; + + let mut glyph_brush = GlyphBrushBuilder::using_font(self.font.clone()).build(); + + glyph_brush.queue(Section::default() + .add_text(Text::new(text).with_scale(size)) + .with_bounds((renderer.game_data.dimensions[0] as f32, renderer.game_data.dimensions[1] as f32)) + ); + match glyph_brush.process_queued(|rect, text_data| { + let tex = renderer.upload_texture(text_data, rect.width(), rect.height(), Format::R8Unorm, Filter::Nearest, SamplerAddressMode::ClampToEdge, renderer.device.clone()); + renderer.game_data.textures.push(tex.clone()); + uploaded_texture = Some(tex); + self.texture_index_counter += 1; + tex_max_size = Some(u32::max(rect.width(), rect.height())); + tex_min_size = Some(u32::min(rect.width(), rect.height())); + }, Self::convert_vertices) { + Ok(BrushAction::Draw(quads)) => { + let mut final_vertices = vec![]; + let mut final_indices: Vec = vec![]; + let mut index_offset = 0; + for quad in quads { + final_vertices.append(&mut quad.iter().map(|v| CPUVertex::VertexText(TextVertex { position: v.position, uv: [v.uv[0], v.uv[1] * (tex_max_size.unwrap() as f32) / (tex_min_size.unwrap() as f32) ] })).collect()); + final_indices.append(&mut [0, 2, 3, 0, 3, 1].iter().map(|x| *x + index_offset).collect()); + index_offset += quad.len() as u32; + } + let mesh = CPUMesh { + vertices: final_vertices, + indices: final_indices, + local_texture_index: Some(self.texture_index_counter - 1), + local_normal_map_index: None, + name: Some("font_texture".to_string()), + }; + let mesh_index = renderer.upload_mesh(mesh, None); + let mesh_handle = MeshHandle { + index: mesh_index, + diffuse_handle: self.texture_index_counter - 1, + normal_handle: None, + original_path: None, + pipeline_index: 1 + }; + uploaded_game_object = Some(self.add_game_object(renderer, mesh_handle)); + }, + Ok(BrushAction::ReDraw) => {}, + Err(BrushError::TextureTooSmall { suggested }) => { println!("texture too small, suggested: {:?}!", suggested); }, + } + + TextObject { + brush: glyph_brush, + texture: uploaded_texture.unwrap(), + game_object: uploaded_game_object.unwrap() + } + } + pub fn clear_level(&mut self, renderer: &mut VulkanRenderer) { self.game_objects.clear(); self.texture_index_counter = 0; @@ -235,4 +257,32 @@ impl TestGame { pub fn print_quat_as_euler(quat: Quaternion) { let euler = Euler::from(quat); print!("({:?},{:?},{:?})", Deg::from(euler.x), Deg::from(euler.y), Deg::from(euler.z)); +} + +pub struct TextObject { + pub brush: GlyphBrush>, + pub texture: Texture, + pub game_object: GameObjectHandle +} + +impl TextObject { + pub fn update_text(&mut self, new_text: &str, new_size: f32, renderer: &mut VulkanRenderer) { + self.brush.queue(Section::default().add_text(Text::new(new_text).with_scale(new_size))); + let mut go_handle = self.game_object; + let mut old_texture = self.texture.clone(); + let mut new_texture = None; + match self.brush.process_queued(|rect, text_data| { + let tex = renderer.blit_and_update_texture(&mut old_texture, text_data, [rect.width(), rect.height(), 1], renderer.device.clone()); + renderer.game_data.textures.push(tex.clone()); + new_texture = Some(tex); + go_handle.get_game_object_mut(renderer).unwrap().textures.texture_index = renderer.game_data.textures.len() - 1; + renderer.update_descriptor_set(&mut go_handle); + }, TestGame::convert_vertices) { + Ok(_) => {}, + Err(e) => println!("Error! {:?}", e), + } + if let Some(tex) = new_texture { + self.texture = tex; + } + } } \ No newline at end of file diff --git a/src/game/player.rs b/src/game/player.rs index 31b60da..d733765 100644 --- a/src/game/player.rs +++ b/src/game/player.rs @@ -52,7 +52,7 @@ impl Camera { // Why? self.proj.y.y *= -1.0; - self.ortho_proj = cgmath::ortho(-width / 2., width / 2., -height / 2., height / 2., -1., 1.); + self.ortho_proj = cgmath::ortho(0., width, 0., height, -1., 1.); // Upload renderer.game_data.line_push_constants.view = self.view.into(); diff --git a/src/vulkan/dds.rs b/src/vulkan/dds.rs index 5cdcb3e..eac6576 100644 --- a/src/vulkan/dds.rs +++ b/src/vulkan/dds.rs @@ -2,9 +2,9 @@ use std::{convert::TryInto, io::Read}; use vulkano::{format::Format, sampler::{Filter, SamplerAddressMode}}; -use super::VulkanRenderer; +use super::{Texture, VulkanRenderer}; -pub fn upload_texture_from_file(path: &str, renderer: &mut VulkanRenderer) -> Result<(), Box> { +pub fn upload_texture_from_file(path: &str, renderer: &mut VulkanRenderer) -> Result> { // Load file let mut tex_file = std::fs::File::open(path)?; let mut tex_bytes: Vec = vec![]; @@ -24,19 +24,18 @@ pub fn upload_texture_from_file(path: &str, renderer: &mut VulkanRenderer) -> Re println!("Texture width: {}, height: {}, bytes: {}", tex_width, tex_height, tex_byte_count); - if is_dxt1 - { - renderer.upload_texture(&tex_bytes[128..], tex_width, tex_height, Format::BC1_RGBUnormBlock, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone()); - } - if is_dx10 - { + let texture = if is_dxt1 { + renderer.upload_texture(&tex_bytes[128..], tex_width, tex_height, Format::BC1_RGBUnormBlock, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone()) + } else if is_dx10 { let dxgi_type = u32::from_ne_bytes(tex_bytes[128..132].try_into()?); assert!(dxgi_type == 83); // BC5 Unorm Typeless - renderer.upload_texture(&tex_bytes[128+20..], tex_width, tex_height, Format::BC5UnormBlock, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone()); - } + renderer.upload_texture(&tex_bytes[128+20..], tex_width, tex_height, Format::BC5UnormBlock, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone()) + } else { + panic!("Unknown texture type!"); + }; - Ok(()) + Ok(texture) } pub fn get_block_size(format: Format) -> Option { diff --git a/src/vulkan/gameobject.rs b/src/vulkan/gameobject.rs index 5cb45a1..541a880 100644 --- a/src/vulkan/gameobject.rs +++ b/src/vulkan/gameobject.rs @@ -11,8 +11,7 @@ use super::pipelines::vs; #[derive(Clone)] pub struct GameObject { pub mesh_index: usize, - pub texture_index: TextureHandle, - pub normal_map_index: TextureHandle, + pub textures: TextureData, pub position: Vector3, pub rotation: Quaternion, pub scale: Vector3, @@ -22,9 +21,20 @@ pub struct GameObject { pub pipeline_index: usize, } +#[derive(Clone)] +pub struct TextureData { + pub texture_index: TextureHandle, + pub normal_map_index: TextureHandle, +} + impl GameObject { pub fn new(mesh: MeshHandle) -> GameObject { - GameObject { mesh_index: mesh.index, texture_index: mesh.diffuse_handle, normal_map_index: mesh.normal_handle.unwrap_or(0), position: Vector3::new(0.0, 0.0, 0.0), + let textures = TextureData { + texture_index: mesh.diffuse_handle, + normal_map_index: mesh.normal_handle.unwrap_or(0), + }; + + GameObject { mesh_index: mesh.index, textures, position: Vector3::new(0.0, 0.0, 0.0), rotation: Quaternion::new(1.0, 0.0, 0.0, 0.0), scale: Vector3::new(1.0, 1.0, 1.0), children: vec![], descriptor_sets: vec![], is_selected: false, pipeline_index: mesh.pipeline_index } } diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 18d769f..577ea95 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -95,6 +95,7 @@ pub struct MeshHandle { } pub(crate) type TextureHandle = usize; +#[derive(Debug, Clone)] pub struct Texture { pub image: Arc>, pub sampler: Arc @@ -331,7 +332,11 @@ impl VulkanRenderer { Arc::new(builder.build().unwrap()) } - + pub fn update_descriptor_set(&mut self, game_object_handle: &mut GameObjectHandle) { + let pipeline_index = game_object_handle.get_game_object_mut(self).unwrap().pipeline_index; + let textures = game_object_handle.get_game_object_mut(self).unwrap().textures.clone(); + self.pipelines[pipeline_index].create_descriptor_set(&textures, self); + } pub fn render_loop(self: &mut Self, new_ubo: vs::ty::ObjectUniformData) { // cleanup previous frame @@ -460,17 +465,16 @@ impl VulkanRenderer { } } - pub fn upload_texture(self: &mut Self, bytes: &[u8], width: u32, height: u32, format: Format, filter: Filter, wrap: SamplerAddressMode, device: Arc) { + pub fn upload_texture(self: &mut Self, bytes: &[u8], width: u32, height: u32, format: Format, filter: Filter, wrap: SamplerAddressMode, device: Arc) -> Texture { let dimensions = Dimensions::Dim2d { width, height }; let usage = ImageUsage { transfer_destination: true, - transfer_source: false, + transfer_source: true, sampled: true, ..ImageUsage::none() }; - let layout = ImageLayout::ShaderReadOnlyOptimal; let mip_maps = if format == Format::R8Uint { MipmapsCount::One } else { MipmapsCount::Log2 }; let (image_view, initializer) = ImmutableImage::uninitialized( @@ -479,7 +483,7 @@ impl VulkanRenderer { format, mip_maps, usage, - layout, + ImageLayout::ShaderReadOnlyOptimal, device.active_queue_families(), ).unwrap(); @@ -548,11 +552,79 @@ impl VulkanRenderer { MipmapMode::Linear, wrap, wrap, wrap, 0.0, 1.0, 0.0, (image_view.mipmap_levels() - 1) as f32).unwrap(); - self.game_data.textures.push(Texture { image: image_view, sampler }); + Texture { image: image_view, sampler } + } + + pub fn blit_and_update_texture(&mut self, texture: &Texture, new_data: &[u8], new_data_dimensions: [u32; 3], device: Arc) -> Texture { + let new_image_usage = ImageUsage { + transfer_destination: true, + transfer_source: true, + sampled: true, + ..ImageUsage::none() + }; + + let (new_image_view, new_image_initializer) = ImmutableImage::uninitialized( + device.clone(), + Dimensions::Dim2d { width: texture.image.dimensions().width(), height: texture.image.dimensions().height() }, + texture.image.format(), + texture.image.mipmap_levels(), + new_image_usage, + ImageLayout::ShaderReadOnlyOptimal, + device.active_queue_families(), + ).unwrap(); + + let new_sub_image = SubImage::new( + Arc::new(new_image_initializer), + 0, + new_image_view.mipmap_levels(), + 0, + 1, + ImageLayout::ShaderReadOnlyOptimal, + ); + + let mut cbb = AutoCommandBufferBuilder::new(device.clone(), self.queue.family()).unwrap(); + + // cbb.copy_image( + // texture.image.clone(), + // [0, 0, 0], + // 0, + // 0, + // new_sub_image.clone(), + // [0, 0, 0], + // 0, + // 0, + // texture.image.dimensions().width_height_depth(), + // 1 + // ).unwrap(); + + let upload_source = CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::transfer_source(), + false, + new_data.iter().cloned(), + ).unwrap(); + + cbb.copy_buffer_to_image_dimensions( + upload_source.clone(), + new_sub_image.clone(), + [0, 0, 0], + new_data_dimensions, + 0, + 1, + 0, + ).unwrap(); + + let cb = cbb.build().unwrap(); + + let future = cb.execute(self.queue.clone()).unwrap(); + + future.flush().unwrap(); + + Texture { image: new_image_view, sampler: texture.sampler.clone() } } pub fn add_game_object(self: &mut Self, mut game_object: GameObject) -> GameObjectHandle { - self.pipelines[game_object.pipeline_index].create_descriptor_set(&mut game_object, self); + game_object.descriptor_sets = self.pipelines[game_object.pipeline_index].create_descriptor_set(&game_object.textures, self); self.game_data.game_objects.push(game_object); GameObjectHandle { diff --git a/src/vulkan/pipelines.rs b/src/vulkan/pipelines.rs index 4937f2e..ecbd237 100644 --- a/src/vulkan/pipelines.rs +++ b/src/vulkan/pipelines.rs @@ -1,6 +1,6 @@ use std::{convert::TryInto, io::{self, ErrorKind, Read, Write}, path::PathBuf, sync::Arc}; -use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::{descriptor::ShaderStages, descriptor_set::PersistentDescriptorSet}, pipeline::{shader::{ShaderModule}}}; +use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::{DescriptorSet, descriptor::ShaderStages, descriptor_set::PersistentDescriptorSet}, pipeline::{shader::{ShaderModule}}}; use vulkano::command_buffer::DynamicState; use vulkano::device::Device; use vulkano::framebuffer::RenderPassAbstract; @@ -14,12 +14,15 @@ use crate::vulkan::{LinePoint, Vertex}; use crate::vulkan::GameData; use crate::VulkanRenderer; +use super::gameobject::TextureData; + type RP = Arc; type GP = Arc; +type DS = Arc; pub trait Drawcall { fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState); - fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer); + fn create_descriptor_set(self: &Self, textures: &TextureData, renderer: &VulkanRenderer) -> Vec; fn recreate_pipeline(self: &mut Self, device: Arc, render_pass: RP); fn get_pipeline(self: &Self) -> &GP; } @@ -152,17 +155,17 @@ impl Drawcall for DefaultShader { } } - fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer) { + fn create_descriptor_set(self: &Self, textures: &TextureData, renderer: &VulkanRenderer) -> Vec { let descriptor_set_layout = self.get_pipeline().descriptor_set_layout(0).unwrap().clone(); - println!("Diff: {:?}, Norm: {:?}", game_object.texture_index, game_object.normal_map_index); + println!("Diff: {:?}, Norm: {:?}", textures.texture_index, textures.normal_map_index); - game_object.descriptor_sets = renderer.uniform_buffers.iter().map(|uniform_buffer| { + renderer.uniform_buffers.iter().map(|uniform_buffer| { let descriptor_set: Arc<(dyn vulkano::descriptor::DescriptorSet + std::marker::Send + std::marker::Sync + 'static)>; let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone()); - let diffuse = &renderer.game_data.textures[game_object.texture_index]; - let normal_map = &renderer.game_data.textures[game_object.normal_map_index]; + let diffuse = &renderer.game_data.textures[textures.texture_index]; + let normal_map = &renderer.game_data.textures[textures.normal_map_index]; descriptor_set = Arc::new(builder .add_buffer(uniform_buffer.clone()).unwrap() @@ -171,7 +174,7 @@ impl Drawcall for DefaultShader { .build().unwrap()); descriptor_set - }).collect(); + }).collect() } fn recreate_pipeline(self: &mut Self, device: Arc, render_pass: RP) { @@ -238,8 +241,8 @@ impl Drawcall for LineShader { game_data.line_push_constants.clone()).unwrap(); } - fn create_descriptor_set(self: &Self, _game_object: &mut GameObject, _renderer: &VulkanRenderer) { - + fn create_descriptor_set(self: &Self, _textures: &TextureData, _renderer: &VulkanRenderer) -> Vec { + vec![] } fn recreate_pipeline(self: &mut Self, device: Arc, render_pass: RP) { @@ -339,14 +342,14 @@ impl Drawcall for TextShader { } } - fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer) { + fn create_descriptor_set(self: &Self, textures: &TextureData, renderer: &VulkanRenderer) -> Vec { let descriptor_set_layout = self.get_pipeline().descriptor_set_layout(0).unwrap().clone(); - game_object.descriptor_sets = renderer.uniform_buffers.iter().map(|uniform_buffer| { + renderer.uniform_buffers.iter().map(|uniform_buffer| { let descriptor_set: Arc<(dyn vulkano::descriptor::DescriptorSet + std::marker::Send + std::marker::Sync + 'static)>; let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone()); - let diffuse = &renderer.game_data.textures[game_object.texture_index]; + let diffuse = &renderer.game_data.textures[textures.texture_index]; descriptor_set = Arc::new(builder .add_buffer(uniform_buffer.clone()).unwrap() @@ -355,7 +358,7 @@ impl Drawcall for TextShader { .build().unwrap()); descriptor_set - }).collect(); + }).collect() } fn recreate_pipeline(self: &mut Self, device: Arc, render_pass: RP) {