1use crate::ecs::Entity;
2use crate::ecs::EntityId;
3use crate::wgpu::texture;
4use cgmath::prelude::*;
5use cgmath::SquareMatrix;
6use std::f32::consts::PI;
7use std::mem;
8use std::{iter, sync::Arc};
9#[cfg(target_arch = "wasm32")]
10use wasm_bindgen::prelude::*;
11use wgpu::util::DeviceExt;
12use winit::{event_loop::ActiveEventLoop, keyboard::KeyCode, window::Window};
13
14#[derive(Default, Copy, Clone)]
15pub enum CameraStrategy {
16 #[default]
17 AllEntities,
18 CameraFollow(EntityId),
19}
20
21#[repr(C)]
22#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
23pub struct Vertex {
24 position: [f32; 3],
25}
26
27fn gen_shape_buffer(points: u16, rotation_deg: f32, size: f32) -> (Vec<Vertex>, Vec<u16>) {
28 if points < 3 {
29 return (
30 vec![
31 Vertex {
32 position: [-0.0868241, 0.49240386, 0.0],
33 },
34 Vertex {
35 position: [-0.49513406, 0.06958647, 0.0],
36 },
37 Vertex {
38 position: [-0.21918549, -0.44939706, 0.0],
39 },
40 Vertex {
41 position: [0.35966998, -0.3473291, 0.0],
42 },
43 Vertex {
44 position: [0.44147372, 0.2347359, 0.0],
45 },
46 ],
47 vec![0, 1, 4, 1, 2, 4, 2, 3, 4],
48 );
49 }
50
51 let mut vertices = Vec::with_capacity(points as usize);
52 let rotation_rad = rotation_deg.to_radians();
53 for i in 0..points {
54 let theta = 2.0 * PI * (i as f32) / (points as f32) + rotation_rad;
55 let x = size * theta.cos();
56 let y = size * theta.sin();
57 vertices.push(Vertex {
58 position: [x, y, 0.0],
59 });
60 }
61
62 let mut indices = Vec::with_capacity((points as usize - 2) * 3);
63 for i in 1..(points - 1) {
64 indices.push(0u16);
65 indices.push(i);
66 indices.push(i + 1);
67 }
68
69 (vertices, indices)
70}
71
72impl Vertex {
73 fn desc() -> wgpu::VertexBufferLayout<'static> {
74 wgpu::VertexBufferLayout {
75 array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
76 step_mode: wgpu::VertexStepMode::Vertex,
77 attributes: &[wgpu::VertexAttribute {
78 offset: 0,
79 shader_location: 0,
80 format: wgpu::VertexFormat::Float32x3,
81 }],
82 }
83 }
84}
85
86#[rustfmt::skip]
87pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::from_cols(
88 cgmath::Vector4::new(1.0, 0.0, 0.0, 0.0),
89 cgmath::Vector4::new(0.0, 1.0, 0.0, 0.0),
90 cgmath::Vector4::new(0.0, 0.0, 0.5, 0.0),
91 cgmath::Vector4::new(0.0, 0.0, 0.5, 1.0),
92);
93
94pub(crate) struct Camera {
95 pub(crate) eye: cgmath::Point3<f32>,
96 pub(crate) target: cgmath::Point3<f32>,
97 pub(crate) up: cgmath::Vector3<f32>,
98 pub(crate) aspect: f32,
99 pub(crate) fovy: f32,
100 pub(crate) znear: f32,
101 pub(crate) zfar: f32,
102}
103
104impl Camera {
105 pub(crate) fn build_view_projection_matrix(&self) -> cgmath::Matrix4<f32> {
106 let view = cgmath::Matrix4::look_at_rh(self.eye, self.target, self.up);
107 let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar);
108 proj * view
109 }
110}
111
112#[repr(C)]
113#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
114pub(crate) struct CameraUniform {
115 pub(crate) view_proj: [[f32; 4]; 4],
116}
117
118impl CameraUniform {
119 pub(crate) fn new() -> Self {
120 Self {
121 view_proj: cgmath::Matrix4::identity().into(),
122 }
123 }
124
125 pub(crate) fn update_view_proj(&mut self, camera: &Camera) {
126 self.view_proj = (OPENGL_TO_WGPU_MATRIX * camera.build_view_projection_matrix()).into();
127 }
128}
129
130pub(crate) struct InstancePosition {
131 pub(crate) position: cgmath::Vector3<f32>,
132 pub(crate) rotation: cgmath::Quaternion<f32>,
133}
134
135#[repr(C)]
136#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
137pub(crate) struct InstancePositionRaw {
138 pub(crate) model: [[f32; 4]; 4],
139}
140
141impl InstancePositionRaw {
142 pub(crate) fn desc() -> wgpu::VertexBufferLayout<'static> {
143 wgpu::VertexBufferLayout {
144 array_stride: mem::size_of::<InstancePositionRaw>() as wgpu::BufferAddress,
145 step_mode: wgpu::VertexStepMode::Instance,
149 attributes: &[
150 wgpu::VertexAttribute {
153 offset: 0,
154 shader_location: 5,
157 format: wgpu::VertexFormat::Float32x4,
158 },
159 wgpu::VertexAttribute {
160 offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
161 shader_location: 6,
162 format: wgpu::VertexFormat::Float32x4,
163 },
164 wgpu::VertexAttribute {
165 offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
166 shader_location: 7,
167 format: wgpu::VertexFormat::Float32x4,
168 },
169 wgpu::VertexAttribute {
170 offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
171 shader_location: 8,
172 format: wgpu::VertexFormat::Float32x4,
173 },
174 ],
175 }
176 }
177}
178
179impl InstancePosition {
180 pub(crate) fn to_raw(&self) -> InstancePositionRaw {
181 InstancePositionRaw {
182 model: (cgmath::Matrix4::from_translation(self.position)
183 * cgmath::Matrix4::from(self.rotation))
184 .into(),
185 }
186 }
187}
188
189pub(crate) struct InstanceColor {
190 pub(crate) color: cgmath::Vector3<f32>,
191}
192
193#[repr(C)]
194#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
195pub(crate) struct InstanceColorRaw {
196 pub(crate) model: [f32; 3],
197}
198
199impl InstanceColorRaw {
200 pub(crate) fn desc() -> wgpu::VertexBufferLayout<'static> {
201 wgpu::VertexBufferLayout {
202 array_stride: mem::size_of::<InstanceColorRaw>() as wgpu::BufferAddress,
203 step_mode: wgpu::VertexStepMode::Instance,
204 attributes: &[wgpu::VertexAttribute {
205 offset: 0,
206 shader_location: 9,
207 format: wgpu::VertexFormat::Float32x3,
208 }],
209 }
210 }
211}
212
213impl InstanceColor {
214 pub(crate) fn to_raw(&self) -> InstanceColorRaw {
215 InstanceColorRaw {
216 model: self.color.into(),
217 }
218 }
219}
220
221pub struct State {
222 surface: wgpu::Surface<'static>,
223 device: wgpu::Device,
224 queue: wgpu::Queue,
225 config: wgpu::SurfaceConfiguration,
226 is_surface_configured: bool,
227 render_pipeline: wgpu::RenderPipeline,
228 vertex_buffer: wgpu::Buffer,
229 index_buffer: wgpu::Buffer,
230 num_indices: u32,
231 #[allow(dead_code)]
232 diffuse_texture: texture::Texture,
233 diffuse_bind_group: wgpu::BindGroup,
234 instance_positions: Vec<InstancePosition>,
235 instance_colors: Vec<InstanceColor>,
236 instance_positions_buffer: wgpu::Buffer,
237 instance_colors_buffer: wgpu::Buffer,
238 camera_strategy: CameraStrategy,
239
240 vertices: Vec<Vertex>,
241 indices: Vec<u16>,
242
243 camera: Camera,
244 camera_uniform: CameraUniform,
245 camera_buffer: wgpu::Buffer,
246 camera_bind_group: wgpu::BindGroup,
247 pub(crate) window: Arc<Window>,
248 renderable_entities: Vec<Entity>,
249}
250
251impl State {
252 pub(crate) async fn new(
253 window: Arc<Window>,
254 renderable_entities: Vec<Entity>,
255 camera_strategy: CameraStrategy,
256 ) -> anyhow::Result<State> {
257 let size = window.inner_size();
258
259 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
262 #[cfg(not(target_arch = "wasm32"))]
263 backends: wgpu::Backends::PRIMARY,
264 #[cfg(target_arch = "wasm32")]
265 backends: wgpu::Backends::GL,
266 ..Default::default()
267 });
268
269 let surface = instance.create_surface(window.clone()).unwrap();
270
271 let adapter = instance
272 .request_adapter(&wgpu::RequestAdapterOptions {
273 power_preference: wgpu::PowerPreference::default(),
274 compatible_surface: Some(&surface),
275 force_fallback_adapter: false,
276 })
277 .await
278 .unwrap();
279 let (device, queue) = adapter
280 .request_device(&wgpu::DeviceDescriptor {
281 label: None,
282 required_features: wgpu::Features::empty(),
283 required_limits: if cfg!(target_arch = "wasm32") {
286 wgpu::Limits::downlevel_webgl2_defaults()
287 } else {
288 wgpu::Limits::default()
289 },
290 memory_hints: Default::default(),
291 trace: wgpu::Trace::Off,
292 })
293 .await
294 .unwrap();
295
296 let surface_caps = surface.get_capabilities(&adapter);
297 let surface_format = surface_caps
301 .formats
302 .iter()
303 .copied()
304 .find(|f| f.is_srgb())
305 .unwrap_or(surface_caps.formats[0]);
306 let config = wgpu::SurfaceConfiguration {
307 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
308 format: surface_format,
309 width: size.width,
310 height: size.height,
311 present_mode: surface_caps.present_modes[0],
312 alpha_mode: surface_caps.alpha_modes[0],
313 view_formats: vec![],
314 desired_maximum_frame_latency: 2,
315 };
316
317 let diffuse_bytes = include_bytes!("happy-tree.png");
318 let diffuse_texture =
319 texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap();
320
321 let texture_bind_group_layout =
322 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
323 entries: &[
324 wgpu::BindGroupLayoutEntry {
325 binding: 0,
326 visibility: wgpu::ShaderStages::FRAGMENT,
327 ty: wgpu::BindingType::Texture {
328 multisampled: false,
329 view_dimension: wgpu::TextureViewDimension::D2,
330 sample_type: wgpu::TextureSampleType::Float { filterable: true },
331 },
332 count: None,
333 },
334 wgpu::BindGroupLayoutEntry {
335 binding: 1,
336 visibility: wgpu::ShaderStages::FRAGMENT,
337 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
338 count: None,
339 },
340 ],
341 label: Some("texture_bind_group_layout"),
342 });
343
344 let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
345 layout: &texture_bind_group_layout,
346 entries: &[
347 wgpu::BindGroupEntry {
348 binding: 0,
349 resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
350 },
351 wgpu::BindGroupEntry {
352 binding: 1,
353 resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
354 },
355 ],
356 label: Some("diffuse_bind_group"),
357 });
358
359 let camera = Camera {
360 eye: (0.0, 1.0, 10.0).into(),
361 target: (0.0, 0.0, 0.0).into(),
362 up: cgmath::Vector3::unit_y(),
363 aspect: config.width as f32 / config.height as f32,
364 fovy: 45.0,
365 znear: 0.1,
366 zfar: 100.0,
367 };
368
369 let mut camera_uniform = CameraUniform::new();
370 camera_uniform.update_view_proj(&camera);
371
372 let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
373 label: Some("Camera Buffer"),
374 contents: bytemuck::cast_slice(&[camera_uniform]),
375 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
376 });
377
378 let camera_bind_group_layout =
379 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
380 entries: &[wgpu::BindGroupLayoutEntry {
381 binding: 0,
382 visibility: wgpu::ShaderStages::VERTEX,
383 ty: wgpu::BindingType::Buffer {
384 ty: wgpu::BufferBindingType::Uniform,
385 has_dynamic_offset: false,
386 min_binding_size: None,
387 },
388 count: None,
389 }],
390 label: Some("camera_bind_group_layout"),
391 });
392
393 let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
394 layout: &camera_bind_group_layout,
395 entries: &[wgpu::BindGroupEntry {
396 binding: 0,
397 resource: camera_buffer.as_entire_binding(),
398 }],
399 label: Some("camera_bind_group"),
400 });
401
402 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
403 label: Some("Shader"),
404 source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
405 });
406
407 let render_pipeline_layout =
408 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
409 label: Some("Render Pipeline Layout"),
410 bind_group_layouts: &[&texture_bind_group_layout, &camera_bind_group_layout],
411 push_constant_ranges: &[],
412 });
413
414 let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
415 label: Some("Render Pipeline"),
416 layout: Some(&render_pipeline_layout),
417 vertex: wgpu::VertexState {
418 module: &shader,
419 entry_point: Some("vs_main"),
420 buffers: &[
421 Vertex::desc(),
422 InstancePositionRaw::desc(),
423 InstanceColorRaw::desc(),
424 ],
425 compilation_options: Default::default(),
426 },
427 fragment: Some(wgpu::FragmentState {
428 module: &shader,
429 entry_point: Some("fs_main"),
430 targets: &[Some(wgpu::ColorTargetState {
431 format: config.format,
432 blend: Some(wgpu::BlendState {
433 color: wgpu::BlendComponent::REPLACE,
434 alpha: wgpu::BlendComponent::REPLACE,
435 }),
436 write_mask: wgpu::ColorWrites::ALL,
437 })],
438 compilation_options: Default::default(),
439 }),
440 primitive: wgpu::PrimitiveState {
441 topology: wgpu::PrimitiveTopology::TriangleList,
442 strip_index_format: None,
443 front_face: wgpu::FrontFace::Ccw,
444 cull_mode: Some(wgpu::Face::Back),
445 polygon_mode: wgpu::PolygonMode::Fill,
448 unclipped_depth: false,
450 conservative: false,
452 },
453 depth_stencil: None,
454 multisample: wgpu::MultisampleState {
455 count: 1,
456 mask: !0,
457 alpha_to_coverage_enabled: false,
458 },
459 multiview: None,
462 cache: None,
464 });
465
466 let (vertices, indices) = gen_shape_buffer(4, 45.0, 0.08);
467
468 let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
469 label: Some("Vertex Buffer"),
470 contents: bytemuck::cast_slice(&vertices),
471 usage: wgpu::BufferUsages::VERTEX,
472 });
473 let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
474 label: Some("Index Buffer"),
475 contents: bytemuck::cast_slice(&indices),
476 usage: wgpu::BufferUsages::INDEX,
477 });
478 let num_indices = indices.len() as u32;
479
480 let (instance_positions, instance_colors): (Vec<InstancePosition>, Vec<InstanceColor>) =
481 renderable_entities
482 .iter()
483 .map(|e| {
484 let position = e.components.position.unwrap();
485 let rotation = cgmath::Quaternion::from_axis_angle(
486 cgmath::Vector3::unit_z(),
487 cgmath::Deg(0.0),
488 );
489 let color = e.components.render.unwrap().rgb;
490
491 let position_3d = cgmath::Vector3 {
492 x: position.x as f32 * 0.1,
493 y: position.y as f32 * 0.1,
494 z: 0.0,
495 };
496 (
497 InstancePosition {
498 position: position_3d,
499 rotation,
500 },
501 InstanceColor { color },
502 )
503 })
504 .unzip();
505 let instance_positions_raw = instance_positions
508 .iter()
509 .map(InstancePosition::to_raw)
510 .collect::<Vec<_>>();
511 let instance_colors_raw = instance_colors
512 .iter()
513 .map(InstanceColor::to_raw)
514 .collect::<Vec<_>>();
515 let instance_positions_buffer =
516 device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
517 label: Some("Instance Position Buffer"),
518 contents: bytemuck::cast_slice(&instance_positions_raw),
519 usage: wgpu::BufferUsages::VERTEX,
520 });
521 let instance_colors_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
522 label: Some("Instance Color Buffer"),
523 contents: bytemuck::cast_slice(&instance_colors_raw),
524 usage: wgpu::BufferUsages::VERTEX,
525 });
526
527 Ok(Self {
528 surface,
529 device,
530 queue,
531 config,
532 is_surface_configured: false,
533 render_pipeline,
534 vertex_buffer,
535 index_buffer,
536 num_indices,
537 diffuse_texture,
538 diffuse_bind_group,
539 vertices,
540 indices,
541 camera,
542 camera_buffer,
543 camera_bind_group,
544 camera_uniform,
545 instance_positions,
546 instance_colors,
547 instance_positions_buffer,
548 instance_colors_buffer,
549 window,
550 renderable_entities,
551 camera_strategy,
552 })
553 }
554
555 pub fn window(&self) -> &Window {
556 &self.window
557 }
558
559 pub(crate) fn resize(&mut self, width: u32, height: u32) {
560 if width > 0 && height > 0 {
561 self.is_surface_configured = true;
562 self.config.width = width;
563 self.config.height = height;
564 self.surface.configure(&self.device, &self.config);
565
566 self.camera.aspect = self.config.width as f32 / self.config.height as f32;
567 }
568 }
569
570 pub(crate) fn handle_key(&mut self, event_loop: &ActiveEventLoop, key: KeyCode, pressed: bool) {
571 if key == KeyCode::Escape && pressed {
572 event_loop.exit();
573 }
574 }
575
576 pub(crate) fn update(&mut self, renderable_entities: Vec<Entity>) {
577 self.renderable_entities = renderable_entities;
578
579 let (instance_positions, instance_colors): (Vec<InstancePosition>, Vec<InstanceColor>) =
580 self.renderable_entities
581 .iter()
582 .map(|e| {
583 let position = e.components.position.unwrap();
584 let render = e.components.render.unwrap();
585 let rotation = cgmath::Quaternion::from_axis_angle(
586 cgmath::Vector3::unit_z(),
587 cgmath::Deg(0.0),
588 );
589
590 let position_3d = cgmath::Vector3 {
591 x: position.x as f32 * 0.1,
592 y: position.y as f32 * 0.1,
593 z: 0.0,
594 };
595 (
596 InstancePosition {
597 position: position_3d,
598 rotation,
599 },
600 InstanceColor { color: render.rgb },
601 )
602 })
603 .unzip();
604 self.instance_positions = instance_positions;
605 self.instance_colors = instance_colors;
606 let instance_position_data = self
607 .instance_positions
608 .iter()
609 .map(InstancePosition::to_raw)
610 .collect::<Vec<_>>();
611 let instance_positions_buffer =
612 self.device
613 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
614 label: Some("Instance Position Buffer"),
615 contents: bytemuck::cast_slice(&instance_position_data),
616 usage: wgpu::BufferUsages::VERTEX,
617 });
618
619 let instance_colors_data = self
620 .instance_colors
621 .iter()
622 .map(InstanceColor::to_raw)
623 .collect::<Vec<_>>();
624 let instance_colors_buffer =
625 self.device
626 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
627 label: Some("Instance Position Buffer"),
628 contents: bytemuck::cast_slice(&instance_colors_data),
629 usage: wgpu::BufferUsages::VERTEX,
630 });
631 self.instance_positions_buffer = instance_positions_buffer;
633 self.instance_colors_buffer = instance_colors_buffer;
634
635 let camera_points =
636 self.renderable_entities
637 .iter()
638 .fold((0.0, 0.0, 0.0, 0.0), |mut acc, e| {
639 if let Some(position) = e.components.position {
640 if position.x < acc.0 {
641 acc.0 = position.x;
642 }
643 if position.x > acc.1 {
644 acc.1 = position.x;
645 }
646 if position.y < acc.2 {
647 acc.2 = position.y;
648 }
649 if position.y > acc.3 {
650 acc.3 = position.y;
651 }
652 }
653 acc
654 });
655 let camera_x_position = (camera_points.0 + camera_points.1) / 2.0;
656 let camera_y_position = (1.0 - camera_points.2 + camera_points.3) / 2.0;
657
658 match self.camera_strategy {
659 CameraStrategy::CameraFollow(entity_id) => {
660 let entity = self
661 .renderable_entities
662 .iter()
663 .find(|e| e.id == entity_id)
664 .unwrap(); let camera_follow_position = entity.components.position.unwrap();
666 self.camera.eye = cgmath::Point3::new(
667 camera_follow_position.x as f32 * 0.1,
668 camera_follow_position.y as f32 * 0.1,
669 4.0,
670 );
671 self.camera.target = cgmath::Point3::new(
672 camera_follow_position.x as f32 * 0.1,
673 camera_follow_position.y as f32 * 0.1,
674 0.0,
675 );
676 self.camera_uniform.update_view_proj(&self.camera);
677 }
678 CameraStrategy::AllEntities => {
679 let game_width = camera_points.1 - camera_points.0;
680 let z_depth = game_width as f32 / 8.1;
681 self.camera.eye =
682 cgmath::Point3::new(camera_x_position * 0.1, camera_y_position * 0.1, z_depth);
683 self.camera.target =
684 cgmath::Point3::new(camera_x_position * 0.1, camera_y_position * 0.1, 0.0);
685 self.camera_uniform.update_view_proj(&self.camera);
686 }
687 }
688
689 self.queue.write_buffer(
690 &self.camera_buffer,
691 0,
692 bytemuck::cast_slice(&[self.camera_uniform]),
693 );
694 }
695
696 pub(crate) fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
697 self.window.request_redraw();
698
699 if !self.is_surface_configured {
701 return Ok(());
702 }
703
704 let output = self.surface.get_current_texture()?;
705 let view = output
706 .texture
707 .create_view(&wgpu::TextureViewDescriptor::default());
708
709 let mut encoder = self
710 .device
711 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
712 label: Some("Render Encoder"),
713 });
714
715 {
716 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
717 label: Some("Render Pass"),
718 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
719 view: &view,
720 resolve_target: None,
721 ops: wgpu::Operations {
722 load: wgpu::LoadOp::Clear(wgpu::Color {
723 r: 1.0,
724 g: 1.0,
725 b: 1.0,
726 a: 1.0,
727 }),
728 store: wgpu::StoreOp::Store,
729 },
730 depth_slice: None,
731 })],
732 depth_stencil_attachment: None,
733 occlusion_query_set: None,
734 timestamp_writes: None,
735 });
736
737 render_pass.set_pipeline(&self.render_pipeline);
738 render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
739 render_pass.set_bind_group(1, &self.camera_bind_group, &[]);
740 render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
741 render_pass.set_vertex_buffer(1, self.instance_positions_buffer.slice(..));
742 render_pass.set_vertex_buffer(2, self.instance_colors_buffer.slice(..));
743 render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
744 render_pass.draw_indexed(
745 0..self.num_indices,
746 0,
747 0..self.instance_positions.len() as _,
748 );
749 }
750
751 self.queue.submit(iter::once(encoder.finish()));
752 output.present();
753
754 Ok(())
755 }
756}