You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: mod.rs
    path of file: ./repos/noxfutura/src/modes/playgame/render/passes/grass_pass
    
    the code of the file until where you have to start completion: use crate::modes::playgame::CameraUniform;
use crate::modes::playgame::GBuffer;
use bengine::*;
use legion::*;
use nox_components::*;
use nox_utils::Frustrum;

// The idea here is to build geometry for grass layers above
// the terrain in a cross-hatch pattern.

pub struct GrassPass {
    grass_template: FloatBuffer<f32>,
    instance_buffer: FloatBuffer<f32>,
    pipeline: gpu::RenderPipeline,
    bind_group: gpu::BindGroup,
    pub models_changed: bool,
}

pub fn build_grass_geometry() -> FloatBuffer<f32> {
    let mut grass_template = FloatBuffer::new(&[3, 2, 1], 100, gpu::BufferUsage::VERTEX);
    grass_template.build();

    let bx = 0.5;
    let bz = 0.0;
    const HEIGHT: f32 = 0.5;
    const GRASS_SPACING: f32 = 0.2;

    let mut by = -0.5;
    while by < 0.51 {
        // Front
        grass_template.add3(bx - 0.5, bz, by);
        grass_template.add2(0.0, 0.0);
        grass_template.add(2.0);
        grass_template.add3(bx + 0.5, bz, by);
        grass_template.add2(1.0, 0.0);
        grass_template.add(2.0);
        grass_template.add3(bx + 0.5, bz + HEIGHT, by);
        grass_template.add2(1.0, 1.0);
        grass_template.add(2.0);

        grass_template.add3(bx - 0.5, bz, by);
        grass_template.add2(0.0, 0.0);
        grass_template.add(2.0);
        grass_template.add3(bx - 0.5, bz + HEIGHT, by);
        grass_template.add2(0.0, 1.0);
        grass_template.add(2.0);
        grass_template.add3(bx + 0.5, bz + HEIGHT, by);
        grass_template.add2(1.0, 1.0);
        grass_template.add(2.0);

        by += GRASS_SPACING;
    }

    let by = 0.5;
    let mut bx = 0.0;
    while bx < 1.01 {
        grass_template.add3(bx, bz, by - 0.5);
        grass_template.add2(0.0, 0.0);
        grass_template.add(4.0);
        grass_template.add3(bx, bz, by + 0.5);
        grass_template.add2(1.0, 0.0);
        grass_template.add(4.0);
        grass_template.add3(bx, bz + HEIGHT, by + 0.5);
        grass_template.add2(1.0, 1.0);
        grass_template.add(4.0);

        grass_template.add3(bx, bz, by - 0.5);
        grass_template.add2(0.0, 0.0);
        grass_template.add(4.0);
        grass_template.add3(bx, bz + HEIGHT, by - 0.5);
        grass_template.add2(0.0, 1.0);
        grass_template.add(4.0);
        grass_template.add3(bx, bz + HEIGHT, by + 0.5);
        grass_template.add2(1.0, 1.0);
        grass_template.add(4.0);
        bx += GRASS_SPACING;
    }

    grass_template.build();

    grass_template
}

impl GrassPass {
    pub fn new(uniforms: &CameraUniform) -> Self {
        // Shader
        let (grass_vert, grass_frag) = helpers::shader_from_bytes(
            bengine::gpu::include_spirv!("grass.vert.spv"),
            bengine::gpu::include_spirv!("grass.frag.spv"),
        );

        // Texture
        let mut tlock = TEXTURES.write();
        let tex_id = tlock.load_texture_from_bytes(include_bytes!("grass.png"), "Grass");

        // Make the grass template (to be instanced)
        let grass_template = build_grass_geometry();

        // Make placeholder instance buffer
        // Format: x/y/z/scale
        let mut instance_buffer = FloatBuffer::new(&[
    
    pub fn new(uniforms: &CameraUniform) -> Self {
        // Shader
        let (grass_vert, grass_frag) = helpers::shader_from_bytes(
            bengine::gpu::include_spirv!("grass.vert.spv"),
            bengine::gpu::include_spirv!("grass.frag.spv"),
        );

        // Texture
        let mut tlock = TEXTURES.write();
        let tex_id = tlock.load_texture_from_bytes(include_bytes!("grass.png"), "Grass");

        // Make the grass template (to be instanced)
        let grass_template = build_grass_geometry();

        // Make placeholder instance buffer
        // Format: x/y/z/scale
        let mut instance_buffer = FloatBuffer::new(&[3, 1], 1000, gpu::BufferUsage::VERTEX);
        instance_buffer.attributes[0].shader_location = 3;
        instance_buffer.attributes[1].shader_location = 4;
        instance_buffer.add3(0.0, 0.0, 0.0);
        instance_buffer.add(0.0);
        instance_buffer.build();

        let dl = RENDER_CONTEXT.read();
        let ctx = dl.as_ref().unwrap();

        let bind_group_layout =
            ctx.device
                .create_bind_group_layout(&gpu::BindGroupLayoutDescriptor {
                    label: None,
                    entries: &[
                        gpu::BindGroupLayoutEntry {
                            binding: 0,
                            visibility: gpu::ShaderStage::VERTEX,
                            ty: gpu::BindingType::UniformBuffer {
                                dynamic: false,
                                min_binding_size: gpu::BufferSize::new(64),
                            },
                            count: None,
                        },
                        gpu::BindGroupLayoutEntry {
                            binding: 1,
                            visibility: gpu::ShaderStage::FRAGMENT,
                            ty: gpu::BindingType::SampledTexture {
                                multisampled: false,
                                dimension: gpu::TextureViewDimension::D2,
                                component_type: gpu::TextureComponentType::Uint,
                            },
                            count: None,
                        },
                        gpu::BindGroupLayoutEntry {
                            binding: 2,
                            visibility: gpu::ShaderStage::FRAGMENT,
                            ty: gpu::BindingType::Sampler { comparison: false },
                            count: None,
                        },
                    ],
                });

        let bind_group = ctx.device.create_bind_group(&gpu::BindGroupDescriptor {
            label: None,
            layout: &bind_group_layout,
            entries: &[
                gpu::BindGroupEntry {
                    binding: 0,
                    resource: gpu::BindingResource::Buffer(uniforms.uniform_buffer.slice(..)),
                },
                gpu::BindGroupEntry {
                    binding: 1,
                    resource: gpu::BindingResource::TextureView(tlock.get_view(tex_id)),
                },
                gpu::BindGroupEntry {
                    binding: 2,
                    resource: gpu::BindingResource::Sampler(tlock.get_sampler(tex_id)),
                },
            ],
        });

        let pipeline_layout = ctx
            .device
            .create_pipeline_layout(&gpu::PipelineLayoutDescriptor {
                label: None,
                bind_group_layouts: &[&bind_group_layout],
                push_constant_ranges: &[],
            });
        let pipeline = ctx
            .device
            .create_render_pipeline(&gpu::RenderPipelineDescriptor {
                label: None,
                layout: Some(&pipeline_layout),
                vertex_stage: gpu::ProgrammableStageDescriptor {
                    module: SHADERS.read().get_module(grass_vert),
                    entry_point: "main",
                },
                fragment_stage: Some(gpu::ProgrammableStageDescriptor {
                    module: SHADERS.read().get_module(grass_frag),
                    entry_point: "main",
                }),
                rasterization_state: Some(gpu::RasterizationStateDescriptor {
                    front_face: gpu::FrontFace::Ccw,
                    cull_mode: gpu::CullMode::None,
                    ..Default::default()
                }),
                primitive_topology: gpu::PrimitiveTopology::TriangleList,
                color_states: &[
                    gpu::ColorStateDescriptor {
                        format: ctx.swapchain_format,
                        color_blend: gpu::BlendDescriptor::REPLACE,
                        alpha_blend: gpu::BlendDescriptor::REPLACE,
                        write_mask: gpu::ColorWrite::ALL,
                    },
                    gpu::ColorStateDescriptor {
                        format: ctx.swapchain_format,
                        color_blend: gpu::BlendDescriptor::REPLACE,
                        alpha_blend: gpu::BlendDescriptor::REPLACE,
                        write_mask: gpu::ColorWrite::ALL,
                    },
                ],
                depth_stencil_state: Some(gpu::DepthStencilStateDescriptor {
                    format: gpu::TextureFormat::Depth32Float,
                    depth_write_enabled: true,
                    depth_compare: gpu::CompareFunction::Less,
                    stencil: gpu::StencilStateDescriptor::default(),
                }),
                vertex_state: gpu::VertexStateDescriptor {
                    index_format: gpu::IndexFormat::Uint16,
                    vertex_buffers: &[
                        grass_template.descriptor(),
                        instance_buffer.instance_descriptor(),
                    ],
                },
                sample_count: 1,
                sample_mask: !0,
                alpha_to_coverage_enabled: false,
            });

        Self {
            grass_template,
            instance_buffer,
            bind_group,
            pipeline,
            models_changed: true,
        }
    }