mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
Cube cleanup and the new generated texture
This commit is contained in:
parent
8f985dd09e
commit
c74f8e8db8
@ -5,6 +5,7 @@ authors = [
|
|||||||
"Dzmitry Malyshau <kvark@mozilla.com>",
|
"Dzmitry Malyshau <kvark@mozilla.com>",
|
||||||
"Joshua Groves <josh@joshgroves.com>",
|
"Joshua Groves <josh@joshgroves.com>",
|
||||||
]
|
]
|
||||||
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# gfx pre-ll examples
|
# gfx pre-ll examples
|
||||||
|
|
||||||
Original gfx-rs examples were growing for years, but then got abandoned once we changed the API to match vulkan:
|
The original gfx-rs examples had grown over several years, but then were abandoned owhen the gfx API was changed to match Vulkan:
|
||||||
https://github.com/gfx-rs/gfx/tree/pre-ll/examples
|
https://github.com/gfx-rs/gfx/tree/pre-ll/examples
|
||||||
|
|
||||||
This is the new home for them, considering `wgpu-rs` to be the spiritual successor of gfx pre-ll.
|
wgpu-rs is considered to be the spiritual successor of gfx pre-ll, so this is the new home for the examples.
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#version 450
|
#version 450
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 v_TexCoord;
|
layout(location = 0) in vec2 v_TexCoord;
|
||||||
layout(location = 0) out vec4 o_Target;
|
layout(location = 0) out vec4 o_Target;
|
||||||
@ -8,6 +7,6 @@ layout(set = 0, binding = 2) uniform sampler s_Color;
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 tex = texture(sampler2D(t_Color, s_Color), v_TexCoord);
|
vec4 tex = texture(sampler2D(t_Color, s_Color), v_TexCoord);
|
||||||
float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
|
float mag = length(v_TexCoord-vec2(0.5));
|
||||||
o_Target = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
|
o_Target = mix(tex, vec4(0.0), mag*mag);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#version 450
|
#version 450
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
|
|
||||||
layout(location = 0) in vec4 a_Pos;
|
layout(location = 0) in vec4 a_Pos;
|
||||||
layout(location = 1) in vec2 a_TexCoord;
|
layout(location = 1) in vec2 a_TexCoord;
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
extern crate cgmath;
|
mod framework;
|
||||||
extern crate wgpu;
|
|
||||||
|
|
||||||
#[path="framework.rs"]
|
|
||||||
mod fw;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -64,6 +60,29 @@ fn create_vertices() -> (Vec<Vertex>, Vec<u16>) {
|
|||||||
(vertex_data.to_vec(), index_data.to_vec())
|
(vertex_data.to_vec(), index_data.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_texels(size: usize) -> Vec<u8> {
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
|
(0 .. size * size)
|
||||||
|
.flat_map(|id| {
|
||||||
|
// get high five for recognizing this ;)
|
||||||
|
let cx = 3.0*(id % size) as f32 / (size - 1) as f32 - 2.0;
|
||||||
|
let cy = 2.0*(id / size) as f32 / (size - 1) as f32 - 1.0;
|
||||||
|
let (mut x, mut y, mut count) = (cx, cy, 0);
|
||||||
|
while count < 0xFF && x*x + y*y < 4.0 {
|
||||||
|
let old_x = x;
|
||||||
|
x = x * x - y * y + cx;
|
||||||
|
y = 2.0 * old_x * y + cy;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
iter::once(0xFF - (count * 5) as u8)
|
||||||
|
.chain(iter::once(0xFF - (count * 15) as u8))
|
||||||
|
.chain(iter::once(0xFF - (count * 50) as u8))
|
||||||
|
.chain(iter::once(1))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
struct Cube {
|
struct Cube {
|
||||||
vertex_buf: wgpu::Buffer,
|
vertex_buf: wgpu::Buffer,
|
||||||
index_buf: wgpu::Buffer,
|
index_buf: wgpu::Buffer,
|
||||||
@ -72,8 +91,8 @@ struct Cube {
|
|||||||
pipeline: wgpu::RenderPipeline,
|
pipeline: wgpu::RenderPipeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fw::Example for Cube {
|
impl framework::Example for Cube {
|
||||||
fn init(device: &mut wgpu::Device) -> Self {
|
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self {
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
let mut init_command_buf = device.create_command_buffer(&wgpu::CommandBufferDescriptor {
|
let mut init_command_buf = device.create_command_buffer(&wgpu::CommandBufferDescriptor {
|
||||||
@ -87,12 +106,12 @@ impl fw::Example for Cube {
|
|||||||
size: (vertex_data.len() * vertex_size) as u32,
|
size: (vertex_data.len() * vertex_size) as u32,
|
||||||
usage: wgpu::BufferUsageFlags::VERTEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
usage: wgpu::BufferUsageFlags::VERTEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||||
});
|
});
|
||||||
vertex_buf.set_sub_data(0, fw::cast_slice(&vertex_data));
|
vertex_buf.set_sub_data(0, framework::cast_slice(&vertex_data));
|
||||||
let index_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
let index_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
size: (index_data.len() * 2) as u32,
|
size: (index_data.len() * 2) as u32,
|
||||||
usage: wgpu::BufferUsageFlags::INDEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
usage: wgpu::BufferUsageFlags::INDEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||||
});
|
});
|
||||||
index_buf.set_sub_data(0, fw::cast_slice(&index_data));
|
index_buf.set_sub_data(0, framework::cast_slice(&index_data));
|
||||||
|
|
||||||
// Create pipeline layout
|
// Create pipeline layout
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
@ -119,10 +138,11 @@ impl fw::Example for Cube {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Create the texture
|
// Create the texture
|
||||||
let texels = [0x20u8, 0xA0, 0xC0, 0xFF];
|
let size = 256u32;
|
||||||
|
let texels = create_texels(size as usize);
|
||||||
let texture_extent = wgpu::Extent3d {
|
let texture_extent = wgpu::Extent3d {
|
||||||
width: 1,
|
width: size,
|
||||||
height: 1,
|
height: size,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
};
|
};
|
||||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
@ -142,8 +162,8 @@ impl fw::Example for Cube {
|
|||||||
wgpu::BufferCopyView {
|
wgpu::BufferCopyView {
|
||||||
buffer: &temp_buf,
|
buffer: &temp_buf,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
row_pitch: 4,
|
row_pitch: 4 * size,
|
||||||
image_height: 1,
|
image_height: size,
|
||||||
},
|
},
|
||||||
wgpu::TextureCopyView {
|
wgpu::TextureCopyView {
|
||||||
texture: &texture,
|
texture: &texture,
|
||||||
@ -164,7 +184,7 @@ impl fw::Example for Cube {
|
|||||||
s_address_mode: wgpu::AddressMode::ClampToEdge,
|
s_address_mode: wgpu::AddressMode::ClampToEdge,
|
||||||
t_address_mode: wgpu::AddressMode::ClampToEdge,
|
t_address_mode: wgpu::AddressMode::ClampToEdge,
|
||||||
mag_filter: wgpu::FilterMode::Nearest,
|
mag_filter: wgpu::FilterMode::Nearest,
|
||||||
min_filter: wgpu::FilterMode::Nearest,
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||||
lod_min_clamp: -100.0,
|
lod_min_clamp: -100.0,
|
||||||
lod_max_clamp: 100.0,
|
lod_max_clamp: 100.0,
|
||||||
@ -177,7 +197,7 @@ impl fw::Example for Cube {
|
|||||||
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
let aspect_ratio = 1.0; //TODO
|
let aspect_ratio = sc_desc.width as f32 / sc_desc.height as f32;
|
||||||
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
|
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
|
||||||
let mx_view = cgmath::Matrix4::look_at(
|
let mx_view = cgmath::Matrix4::look_at(
|
||||||
cgmath::Point3::new(1.5f32, -5.0, 3.0),
|
cgmath::Point3::new(1.5f32, -5.0, 3.0),
|
||||||
@ -186,7 +206,7 @@ impl fw::Example for Cube {
|
|||||||
);
|
);
|
||||||
let mx_total = mx_projection * mx_view;
|
let mx_total = mx_projection * mx_view;
|
||||||
let mx_raw: &[f32; 16] = mx_total.as_ref();
|
let mx_raw: &[f32; 16] = mx_total.as_ref();
|
||||||
uniform_buf.set_sub_data(0, fw::cast_slice(&mx_raw[..]));
|
uniform_buf.set_sub_data(0, framework::cast_slice(&mx_raw[..]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create bind group
|
// Create bind group
|
||||||
@ -212,7 +232,8 @@ impl fw::Example for Cube {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Create the render pipeline
|
// Create the render pipeline
|
||||||
let (vs_bytes, fs_bytes) = fw::load_glsl_pair("cube");
|
let vs_bytes = framework::load_glsl("cube.vert", wgpu::ShaderStage::Vertex);
|
||||||
|
let fs_bytes = framework::load_glsl("cube.frag", wgpu::ShaderStage::Fragment);
|
||||||
let vs_module = device.create_shader_module(&vs_bytes);
|
let vs_module = device.create_shader_module(&vs_bytes);
|
||||||
let fs_module = device.create_shader_module(&fs_bytes);
|
let fs_module = device.create_shader_module(&fs_bytes);
|
||||||
|
|
||||||
@ -237,7 +258,7 @@ impl fw::Example for Cube {
|
|||||||
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
attachments_state: wgpu::AttachmentsState {
|
attachments_state: wgpu::AttachmentsState {
|
||||||
color_attachments: &[wgpu::Attachment {
|
color_attachments: &[wgpu::Attachment {
|
||||||
format: fw::SWAP_CHAIN_FORMAT,
|
format: sc_desc.format,
|
||||||
samples: 1,
|
samples: 1,
|
||||||
}],
|
}],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
@ -276,7 +297,7 @@ impl fw::Example for Cube {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _event: fw::winit::WindowEvent) {
|
fn update(&mut self, _event: framework::winit::WindowEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
|
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
|
||||||
@ -287,7 +308,7 @@ impl fw::Example for Cube {
|
|||||||
attachment: &frame.view,
|
attachment: &frame.view,
|
||||||
load_op: wgpu::LoadOp::Clear,
|
load_op: wgpu::LoadOp::Clear,
|
||||||
store_op: wgpu::StoreOp::Store,
|
store_op: wgpu::StoreOp::Store,
|
||||||
clear_color: wgpu::Color::GREEN,
|
clear_color: wgpu::Color { r: 0.1, g: 0.2, b: 0.3, a: 1.0 },
|
||||||
}],
|
}],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
@ -306,5 +327,5 @@ impl fw::Example for Cube {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
fw::run::<Cube>("cube");
|
framework::run::<Cube>("cube");
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
extern crate env_logger;
|
pub use wgpu_native::winit;
|
||||||
extern crate glsl_to_spirv;
|
|
||||||
extern crate log;
|
|
||||||
extern crate wgpu_native;
|
|
||||||
|
|
||||||
pub use self::wgpu_native::winit;
|
use log::info;
|
||||||
|
|
||||||
use self::log::info;
|
|
||||||
|
|
||||||
|
|
||||||
pub const SWAP_CHAIN_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::B8g8r8a8Unorm;
|
|
||||||
|
|
||||||
pub fn cast_slice<T>(data: &[T]) -> &[u8] {
|
pub fn cast_slice<T>(data: &[T]) -> &[u8] {
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
@ -19,33 +12,32 @@ pub fn cast_slice<T>(data: &[T]) -> &[u8] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_glsl_pair(name: &str) -> (Vec<u8>, Vec<u8>) {
|
pub fn load_glsl(name: &str, stage: wgpu::ShaderStage) -> Vec<u8> {
|
||||||
use self::glsl_to_spirv::{ShaderType, compile};
|
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
let base_path = PathBuf::from("data").join(name);
|
let ty = match stage {
|
||||||
let code_vs = read_to_string(base_path.with_extension("vert")).unwrap();
|
wgpu::ShaderStage::Vertex => glsl_to_spirv::ShaderType::Vertex,
|
||||||
let code_fs = read_to_string(base_path.with_extension("frag")).unwrap();
|
wgpu::ShaderStage::Fragment => glsl_to_spirv::ShaderType::Fragment,
|
||||||
|
wgpu::ShaderStage::Compute => glsl_to_spirv::ShaderType::Compute,
|
||||||
let mut output_vs = compile(&code_vs, ShaderType::Vertex).unwrap();
|
};
|
||||||
let mut output_fs = compile(&code_fs, ShaderType::Fragment).unwrap();
|
let path = PathBuf::from("data").join(name);
|
||||||
|
let code = read_to_string(path).unwrap();
|
||||||
let (mut spv_vs, mut spv_fs) = (Vec::new(), Vec::new());
|
let mut output = glsl_to_spirv::compile(&code, ty).unwrap();
|
||||||
output_vs.read_to_end(&mut spv_vs).unwrap();
|
let mut spv = Vec::new();
|
||||||
output_fs.read_to_end(&mut spv_fs).unwrap();
|
output.read_to_end(&mut spv).unwrap();
|
||||||
(spv_vs, spv_fs)
|
spv
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Example {
|
pub trait Example {
|
||||||
fn init(device: &mut wgpu::Device) -> Self;
|
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self;
|
||||||
fn update(&mut self, event: winit::WindowEvent);
|
fn update(&mut self, event: winit::WindowEvent);
|
||||||
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device);
|
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<E: Example>(title: &str) {
|
pub fn run<E: Example>(title: &str) {
|
||||||
use self::wgpu_native::winit::{
|
use wgpu_native::winit::{
|
||||||
Event, ElementState, EventsLoop, KeyboardInput, Window, WindowEvent, VirtualKeyCode
|
Event, ElementState, EventsLoop, KeyboardInput, Window, WindowEvent, VirtualKeyCode
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,9 +53,6 @@ pub fn run<E: Example>(title: &str) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("Initializing the example...");
|
|
||||||
let mut example = E::init(&mut device);
|
|
||||||
|
|
||||||
info!("Initializing the window...");
|
info!("Initializing the window...");
|
||||||
let mut events_loop = EventsLoop::new();
|
let mut events_loop = EventsLoop::new();
|
||||||
let window = Window::new(&events_loop).unwrap();
|
let window = Window::new(&events_loop).unwrap();
|
||||||
@ -74,12 +63,16 @@ pub fn run<E: Example>(title: &str) {
|
|||||||
.to_physical(window.get_hidpi_factor());
|
.to_physical(window.get_hidpi_factor());
|
||||||
|
|
||||||
let surface = instance.create_surface(&window);
|
let surface = instance.create_surface(&window);
|
||||||
let mut swap_chain = device.create_swap_chain(&surface, &wgpu::SwapChainDescriptor {
|
let sc_desc = wgpu::SwapChainDescriptor {
|
||||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
||||||
format: SWAP_CHAIN_FORMAT,
|
format: wgpu::TextureFormat::B8g8r8a8Unorm,
|
||||||
width: size.width as u32,
|
width: size.width as u32,
|
||||||
height: size.height as u32,
|
height: size.height as u32,
|
||||||
});
|
};
|
||||||
|
let mut swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||||
|
|
||||||
|
info!("Initializing the example...");
|
||||||
|
let mut example = E::init(&mut device, &sc_desc);
|
||||||
|
|
||||||
info!("Entering render loop...");
|
info!("Entering render loop...");
|
||||||
let mut running = true;
|
let mut running = true;
|
||||||
|
@ -34,6 +34,8 @@ use std::{iter, slice};
|
|||||||
use std::thread::ThreadId;
|
use std::thread::ThreadId;
|
||||||
|
|
||||||
|
|
||||||
|
const BITS_PER_BYTE: u32 = 8;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub enum LoadOp {
|
pub enum LoadOp {
|
||||||
@ -443,7 +445,8 @@ pub extern "C" fn wgpu_command_buffer_copy_buffer_to_texture(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes_per_texel = conv::map_texture_format(dst_texture.format).surface_desc().bits as u32 / 8;
|
let bytes_per_texel = conv::map_texture_format(dst_texture.format)
|
||||||
|
.surface_desc().bits as u32 / BITS_PER_BYTE;
|
||||||
let buffer_width = source.row_pitch / bytes_per_texel;
|
let buffer_width = source.row_pitch / bytes_per_texel;
|
||||||
assert_eq!(source.row_pitch % bytes_per_texel, 0);
|
assert_eq!(source.row_pitch % bytes_per_texel, 0);
|
||||||
let region = hal::command::BufferImageCopy {
|
let region = hal::command::BufferImageCopy {
|
||||||
|
@ -2,7 +2,6 @@ use crate::{
|
|||||||
binding_model, command, pipeline, resource, Color,
|
binding_model, command, pipeline, resource, Color,
|
||||||
Extent3d, Origin3d,
|
Extent3d, Origin3d,
|
||||||
};
|
};
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn map_buffer_usage(
|
pub fn map_buffer_usage(
|
||||||
@ -454,10 +453,7 @@ pub fn map_wrap(address: resource::AddressMode) -> hal::image::WrapMode {
|
|||||||
match address {
|
match address {
|
||||||
Am::ClampToEdge => W::Clamp,
|
Am::ClampToEdge => W::Clamp,
|
||||||
Am::Repeat => W::Tile,
|
Am::Repeat => W::Tile,
|
||||||
Am::MirrorRepeat => {
|
Am::MirrorRepeat => W::Mirror,
|
||||||
warn!("MirrorRepeat isn't supported yet");
|
|
||||||
W::Tile
|
|
||||||
}
|
|
||||||
Am::ClampToBorderColor => W::Border,
|
Am::ClampToBorderColor => W::Border,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1047,8 +1047,8 @@ pub extern "C" fn wgpu_device_create_render_pipeline(
|
|||||||
let desc_vbs = unsafe {
|
let desc_vbs = unsafe {
|
||||||
slice::from_raw_parts(desc.vertex_buffer_state.vertex_buffers, desc.vertex_buffer_state.vertex_buffers_count)
|
slice::from_raw_parts(desc.vertex_buffer_state.vertex_buffers, desc.vertex_buffer_state.vertex_buffers_count)
|
||||||
};
|
};
|
||||||
let mut vertex_buffers: Vec<hal::pso::VertexBufferDesc> = Vec::with_capacity(desc_vbs.len());
|
let mut vertex_buffers = Vec::with_capacity(desc_vbs.len());
|
||||||
let mut attributes: Vec<hal::pso::AttributeDesc> = Vec::new();
|
let mut attributes = Vec::new();
|
||||||
for (i, vb_state) in desc_vbs.iter().enumerate() {
|
for (i, vb_state) in desc_vbs.iter().enumerate() {
|
||||||
if vb_state.attributes_count == 0 {
|
if vb_state.attributes_count == 0 {
|
||||||
continue
|
continue
|
||||||
|
Loading…
Reference in New Issue
Block a user